import { expect } from '@playwright/test';
import { test } from '../baseFixtures.ts';
import { readeruser, stevenuser } from '../defaults.ts';
import {
  activateCalendarView,
  activateTableView,
  clearTableFilters,
  clickButtonIfVisible,
  clickOnRowMenu,
  loadTab,
  navigate,
  openDetailAction,
  openFilterDrawer,
  setTableChoiceFilter,
  showCalendarView,
  showParametricView,
  showTableView
} from '../helpers.ts';
import { doCachedLogin } from '../login.ts';

test('Purchasing - Index', async ({ browser }) => {
  const page = await doCachedLogin(browser, { url: 'purchasing/index/' });

  // Purchase Orders tab
  await loadTab(page, 'Purchase Orders');
  await showParametricView(page);
  await showCalendarView(page);
  await showTableView(page);

  // Check default filters are applied
  // By default, only outstanding orders are visible
  await page.getByText(/1 - \d+ \/ \d+/).waitFor();

  // Clearing the filters, more orders should be visible
  await clearTableFilters(page);
  await page.getByText(/1 - \d\d \/ \d\d/).waitFor();

  // Suppliers tab
  await loadTab(page, 'Suppliers');
  await showParametricView(page);
  await showTableView(page);

  // Check for expected values
  await clearTableFilters(page);
  await page.getByRole('cell', { name: 'DigiKey DigiKey' }).first().waitFor();

  // Supplier parts tab
  await loadTab(page, 'Supplier Parts');
  await showParametricView(page);
  await showTableView(page);

  // Check for expected values
  await clearTableFilters(page);
  await page
    .getByRole('textbox', { name: 'table-search-input' })
    .fill('R_100K_0402');
  await page.getByText('R_100K_0402_1%').first().waitFor();
  await page.getByRole('cell', { name: 'RR05P100KDTR-ND' }).first().waitFor();

  // Manufacturers tab
  await loadTab(page, 'Manufacturers');
  await showParametricView(page);
  await showTableView(page);

  // Check for expected values
  await clearTableFilters(page);
  await page
    .getByRole('cell', { name: 'Hammond Manufacturing Hammond' })
    .first()
    .waitFor();

  // Manufacturer parts tab
  await loadTab(page, 'Manufacturer Parts');
  await showParametricView(page);
  await showTableView(page);

  // Check for expected values
  await clearTableFilters(page);
  await page.getByRole('cell', { name: 'ERA-2AEB104X' }).first().waitFor();
  await page
    .getByRole('cell', { name: 'Bourns Inc. Bourns Inc.' })
    .first()
    .waitFor();
});

test('Purchasing - Parameters', async ({ browser }) => {
  const page = await doCachedLogin(browser, {
    url: 'purchasing/purchase-order/11/parameters',
    user: stevenuser
  });

  // Create a new parameter against this purchase order
  await page
    .getByRole('button', { name: 'action-menu-add-parameters' })
    .click();
  await page
    .getByRole('menuitem', {
      name: 'action-menu-add-parameters-create-parameter'
    })
    .click();

  // Check for button to add a new template
  await page
    .getByRole('button', {
      name: 'action-button-create-new-parameter-template'
    })
    .click();
  await page
    .getByText('Create New Parameter Template', { exact: true })
    .first()
    .waitFor();
  await page.getByRole('textbox', { name: 'text-field-description' }).waitFor();
  await page.getByRole('textbox', { name: 'text-field-choices' }).waitFor();
  await page
    .getByLabel('Create New Parameter Template')
    .getByRole('button', { name: 'Cancel' })
    .click();

  // We will use a "SelectionList" to choose the value here

  // Select the template
  await page
    .getByRole('combobox', { name: 'related-field-template' })
    .fill('animal');
  await page.getByRole('option', { name: 'Animal Select an animal' }).click();

  // Select an animal
  await page.getByRole('combobox', { name: 'related-field-data' }).fill('cat');
  await page.getByRole('option', { name: 'Caracal' }).click();

  // Add a note and submit the form
  await page
    .getByRole('textbox', { name: 'text-field-note' })
    .fill('The caracal is an interesting beast');
  await page.getByRole('button', { name: 'Submit' }).click();

  // Let's edit this parameter to ensure the "edit" form works as expected
  await clickOnRowMenu(await page.getByRole('cell', { name: 'Caracal' }));
  await page.getByRole('menuitem', { name: 'Edit' }).click();

  await page.getByRole('combobox', { name: 'related-field-data' }).fill('ox');
  await page.getByRole('option', { name: 'Fennec Fox' }).click();
  await page.getByRole('button', { name: 'Submit' }).click();

  // Finally, delete the parameter
  await clickOnRowMenu(await page.getByRole('cell', { name: 'Fennec Fox' }));
  await page.getByRole('menuitem', { name: 'Delete' }).click();
  await page.getByRole('button', { name: 'Delete', exact: true }).click();
});

test('Purchasing - Manufacturer Parts', async ({ browser }) => {
  const page = await doCachedLogin(browser, {
    url: 'purchasing/index/manufacturer-parts'
  });

  await page
    .getByRole('textbox', { name: 'table-search-input' })
    .fill('CPF0402B100KE1');
  await page.getByText('R_100K_0402_1%').first().waitFor();
  await page.getByRole('cell', { name: 'CPF0402B100KE1' }).waitFor();

  // Check data exporter
  await page.getByRole('button', { name: 'table-export-data' }).click();
  await page.getByText('Select export plugin').waitFor();
  await page
    .getByRole('combobox', { name: 'choice-field-export_plugin' })
    .fill('CSV');
  await page.getByRole('button', { name: 'Export', exact: true }).click();
  await page.getByText('Process completed successfully').waitFor();

  await loadTab(page, 'Manufacturers');
  await page.getByText('Murata Electronics').waitFor();
});

test('Purchase Orders - General', async ({ browser }) => {
  const page = await doCachedLogin(browser);

  await page.getByRole('tab', { name: 'Purchasing' }).click();
  await page.waitForURL('**/purchasing/index/**');

  await page.getByRole('cell', { name: 'PO0012' }).click();
  await page.waitForTimeout(200);

  await loadTab(page, 'Line Items');
  await loadTab(page, 'Received Stock');
  await loadTab(page, 'Parameters');
  await loadTab(page, 'Attachments');

  await page.getByRole('tab', { name: 'Purchasing' }).click();
  await loadTab(page, 'Suppliers');
  await page.getByText('Arrow', { exact: true }).click();
  await page.waitForTimeout(200);

  await loadTab(page, 'Supplied Parts');
  await loadTab(page, 'Purchase Orders');
  await loadTab(page, 'Stock Items');
  await loadTab(page, 'Contacts');
  await loadTab(page, 'Addresses');
  await loadTab(page, 'Attachments');

  await page.getByRole('tab', { name: 'Purchasing' }).click();
  await loadTab(page, 'Manufacturers');
  await page.getByText('AVX Corporation').click();
  await page.waitForTimeout(200);

  await loadTab(page, 'Addresses');
  await page.getByRole('cell', { name: 'West Branch' }).click();
  await page.locator('.mantine-ScrollArea-root').click();
  await page
    .getByRole('row', { name: 'West Branch Yes Surf Avenue 9' })
    .getByRole('button')
    .click();
  await page.getByRole('menuitem', { name: 'Edit' }).click();

  await page.getByLabel('text-field-title', { exact: true }).waitFor();
  await page.getByLabel('text-field-line2', { exact: true }).waitFor();

  // Read the current value of the cell, to ensure we always *change* it!
  const value = await page
    .getByLabel('text-field-line2', { exact: true })
    .inputValue();
  await page
    .getByLabel('text-field-line2', { exact: true })
    .fill(value == 'old' ? 'new' : 'old');

  await page.getByRole('button', { name: 'Submit' }).isEnabled();

  await page.getByRole('button', { name: 'Submit' }).click();
  await page.getByRole('tab', { name: 'Details' }).waitFor();
});

test('Purchase Orders - Table', async ({ browser }) => {
  const page = await doCachedLogin(browser);

  await page.getByRole('tab', { name: 'Purchasing' }).click();
  await page.waitForURL('**/purchasing/index/**');

  await loadTab(page, 'Purchase Orders');
  await activateTableView(page);

  await clearTableFilters(page);

  // Check for expected values
  await page.getByRole('cell', { name: 'PO0014' }).waitFor();
  await page.getByText('Wire-E-Coyote').waitFor();
  await page.getByText('Cancelled').first().waitFor();
  await page.getByText('Pending').first().waitFor();
  await page.getByText('On Hold').first().waitFor();

  // Filter by 'has start date'
  await setTableChoiceFilter(page, 'Has Start Date', 'Yes');
  await page.getByRole('cell', { name: 'Scheduled purchase order' }).waitFor();

  // Click through to a particular purchase order
  await page.getByRole('cell', { name: 'PO0015' }).click();
  await page.getByRole('button', { name: 'Issue Order' }).waitFor();

  // Expected values
  await page.getByText('2025-06-12').waitFor(); // Start Date
  await page.getByText('2025-07-17').waitFor(); // Target Date
});

test('Purchase Orders - Calendar', async ({ browser }) => {
  const page = await doCachedLogin(browser);

  await page.getByRole('tab', { name: 'Purchasing' }).click();
  await page.waitForURL('**/purchasing/index/**');
  await loadTab(page, 'Purchase Orders');

  // Ensure view is in "calendar" mode
  await activateCalendarView(page);

  // Check for expected components
  await page.getByLabel('action-button-previous-month').waitFor();
  await page.getByLabel('action-button-next-month').waitFor();

  await page.getByLabel('calendar-select-month').click();
  await page.getByRole('button', { name: 'Jan' }).waitFor();
  await page.getByRole('button', { name: 'Feb' }).waitFor();
  await page.getByRole('button', { name: 'Dec' }).click();

  await page.getByText('December').first().waitFor();

  // Put back into table view
  await activateTableView(page);
});

test('Purchase Orders - Barcodes', async ({ browser }) => {
  const page = await doCachedLogin(browser, {
    url: 'purchasing/purchase-order/13/detail'
  });

  await page.getByRole('button', { name: 'Issue Order' }).waitFor();

  // Display QR code
  await openDetailAction(page, 'barcode', 'view');
  await page.getByRole('img', { name: 'QR Code' }).waitFor();
  await page.getByRole('banner').getByRole('button').click();

  // Un-link barcode if a link exists
  await page.getByLabel('action-menu-barcode-actions').click();
  await page.waitForTimeout(100);

  if (
    await page
      .getByLabel('action-menu-barcode-actions-unlink-barcode')
      .isVisible()
  ) {
    await page.getByLabel('action-menu-barcode-actions-unlink-barcode').click();
    await page.getByRole('button', { name: 'Unlink Barcode' }).click();
    await page.waitForTimeout(100);
  } else {
    await page.keyboard.press('Escape');
  }

  // Link to barcode
  await openDetailAction(page, 'barcode', 'link-barcode');

  await page.getByLabel('barcode-input-scanner').click();

  // Simulate barcode scan
  await page.getByPlaceholder('Enter barcode data').fill('1234567890');
  await page.getByRole('button', { name: 'Scan', exact: true }).click();
  await page.waitForTimeout(250);

  await page.getByRole('button', { name: 'Issue Order' }).waitFor();

  // Ensure we can scan back to this page, with the associated barcode
  await page.getByRole('tab', { name: 'Sales' }).click();
  await page.waitForTimeout(250);

  await page.getByRole('button', { name: 'barcode-scan-button-any' }).click();

  await page.getByPlaceholder('Enter barcode data').fill('1234567890');
  await page.getByRole('button', { name: 'Scan', exact: true }).click();

  await page.getByText('Purchase Order: PO0013', { exact: true }).waitFor();

  // Unlink barcode
  await openDetailAction(page, 'barcode', 'unlink-barcode');
  await page.getByRole('heading', { name: 'Unlink Barcode' }).waitFor();
  await page.getByText('This will remove the link to').waitFor();
  await page.getByRole('button', { name: 'Unlink Barcode' }).click();
  await page.waitForTimeout(250);
  await page.getByRole('button', { name: 'Issue Order' }).waitFor();
});

test('Purchase Orders - Filters', async ({ browser }) => {
  const page = await doCachedLogin(browser, {
    user: readeruser
  });

  await page.getByRole('tab', { name: 'Purchasing' }).click();
  await page.waitForURL('**/purchasing/index/**');

  await loadTab(page, 'Purchase Orders');
  await activateTableView(page);

  // Open filters drawer
  await openFilterDrawer(page);
  await clickButtonIfVisible(page, 'Clear Filters');

  await page.getByRole('button', { name: 'Add Filter' }).click();

  // Check for expected filter options
  await page.getByPlaceholder('Select filter').fill('before');
  await page.getByRole('option', { name: 'Created Before' }).waitFor();
  await page.getByRole('option', { name: 'Completed Before' }).waitFor();
  await page.getByRole('option', { name: 'Target Date Before' }).waitFor();

  await page.getByPlaceholder('Select filter').fill('after');
  await page.getByRole('option', { name: 'Created After' }).waitFor();
  await page.getByRole('option', { name: 'Completed After' }).waitFor();
  await page.getByRole('option', { name: 'Target Date After' }).waitFor();
});

test('Purchase Orders - Price Breaks', async ({ browser }) => {
  const page = await doCachedLogin(browser, {
    url: 'purchasing/purchase-order/14/line-items'
  });

  await page
    .getByRole('button', { name: 'action-button-add-line-item' })
    .click();
  await page.getByLabel('related-field-part').fill('002.01');
  await page.getByRole('option', { name: 'PCBWOY PCB-002.01' }).click();

  // Expected price-break values
  const priceBreaks = {
    1: 500,
    8: 500,
    10: 565,
    99: 565,
    999: 205
  };

  for (const [qty, expectedPrice] of Object.entries(priceBreaks)) {
    await page.getByLabel('number-field-quantity').fill(qty);

    await expect(
      page.getByRole('textbox', { name: 'number-field-purchase_price' })
    ).toHaveAttribute('placeholder', expectedPrice.toString(), {
      timeout: 500
    });
  }

  // Auto-fill the suggested sale price
  await page.getByLabel('field-purchase_price-accept-placeholder').click();

  await expect(
    page.getByRole('textbox', { name: 'number-field-purchase_price' })
  ).toHaveValue('205', { timeout: 500 });
});

test('Purchase Orders - Order Parts', async ({ browser }) => {
  const page = await doCachedLogin(browser);

  // Open "Order Parts" wizard from the "parts" table
  await page.getByRole('tab', { name: 'Parts' }).click();
  await page.waitForURL('**/part/category/index/**');

  await page
    .getByLabel('panel-tabs-partcategory')
    .getByRole('tab', { name: 'Parts' })
    .click();

  // Select multiple parts
  for (let ii = 1; ii < 5; ii++) {
    await page.getByLabel(`Select record ${ii}`, { exact: true }).click();
  }

  await openDetailAction(page, 'part', 'order-parts');

  await page
    .getByRole('heading', { name: 'Order Parts' })
    .locator('div')
    .first()
    .waitFor();
  await page.getByRole('banner').getByRole('button').click();

  // Open "Order Parts" wizard from the "Stock Items" table
  await page.getByRole('tab', { name: 'Stock' }).click();
  await loadTab(page, 'Stock Items');

  // Select multiple stock items
  for (let ii = 2; ii < 7; ii += 2) {
    await page.getByLabel(`Select record ${ii}`, { exact: true }).click();
  }

  await page.getByRole('button', { name: 'action-button-order-items' }).click();
  await page.getByRole('banner').getByRole('button').click();

  // Order from the part detail page
  await navigate(page, 'part/69/');
  await page.waitForURL('**/part/69/**');

  await openDetailAction(page, 'stock', 'order');

  // Select supplier part
  await page.getByLabel('related-field-supplier_part').click();
  await page
    .getByRole('option', { name: 'Thumbnail DigiKey WM1731-ND' })
    .click();

  // Option to create a new supplier part
  await page.getByLabel('action-button-new-supplier-part').click();
  await page.getByLabel('related-field-supplier', { exact: true }).click();
  await page.getByText('Future').click();
  await page.getByRole('button', { name: 'Cancel' }).click();

  // Select purchase order
  await page.getByLabel('related-field-purchase_order').click();
  await page.getByText('PO0001').click();

  // Option to create a new purchase order
  await page.getByLabel('action-button-new-purchase-order').click();
  await page.getByLabel('related-field-project_code').click();
  await page.getByText('PRJ-PHO').click();
  await page.getByRole('button', { name: 'Cancel' }).click();

  await page.getByLabel('number-field-quantity').fill('100');

  // Add the part to the purchase order
  await page.getByLabel('action-button-add-to-selected').click();
  await page.getByLabel('number-field-quantity').fill('100');
  await page.waitForTimeout(250);
  await page.getByRole('button', { name: 'Submit' }).click();
  await page
    .getByText('All selected parts added to a purchase order')
    .waitFor();
});

/**
 * Tests for receiving items against a purchase order
 */
test('Purchase Orders - Receive Items', async ({ browser }) => {
  const page = await doCachedLogin(browser);

  await page.getByRole('tab', { name: 'Purchasing' }).click();
  await page.waitForURL('**/purchasing/index/**');

  await page.getByRole('cell', { name: 'PO0014' }).click();

  await loadTab(page, 'Order Details');

  // Select all line items to receive
  await loadTab(page, 'Line Items');

  await page.getByRole('cell', { name: '002.02-PCB' }).waitFor();
  await page.getByLabel('Select all records').click();
  await page.waitForTimeout(100);
  await page.getByLabel('action-button-receive-items').click();

  // Check for display of individual locations
  await page.getByText('Parts Bins').first().waitFor();
  await page.getByText('Room 101').first().waitFor();
  await page.getByText('Mechanical Lab').first().waitFor();

  await page.getByRole('button', { name: 'Cancel' }).click();

  // Let's actually receive an item (with custom values)
  await navigate(page, 'purchasing/purchase-order/2/line-items');

  const cell = await page.getByText('Red Paint', { exact: true });

  // First, ensure that the row has sufficient quantity to receive
  // This is required to ensure the robustness of this test,
  // as the test data may be modified by other tests
  await clickOnRowMenu(cell);
  await page.getByRole('menuitem', { name: 'Edit' }).click();
  const quantityInput = await page.getByRole('textbox', {
    name: 'number-field-quantity'
  });
  const quantity = Number.parseInt(await quantityInput.inputValue());
  await quantityInput.fill((quantity + 100).toString());

  await page.getByRole('button', { name: 'Submit' }).click();
  await page.getByText('Item Updated').waitFor();

  // Now, receive the items
  await clickOnRowMenu(cell);
  await page.getByRole('menuitem', { name: 'Receive line item' }).click();

  // Select destination location
  await page.getByLabel('tree-field-location').fill('factory');
  await page.getByText('Factory', { exact: true }).click();

  // Receive only a *single* item
  await page.getByLabel('number-field-quantity').fill('1');
  await page.waitForTimeout(500);

  // Assign custom information
  await page.getByLabel('action-button-assign-batch-').click();
  await page.getByLabel('action-button-adjust-packaging').click();
  await page.getByLabel('action-button-change-status').click();
  await page.getByLabel('action-button-add-note').click();

  await page
    .getByLabel('text-field-batch_code', { exact: true })
    .fill('my-batch-code');
  await page.getByLabel('text-field-packaging', { exact: true }).fill('bucket');
  await page
    .getByLabel('text-field-note', { exact: true })
    .fill('The quick brown fox');
  await page.getByLabel('choice-field-status').click();
  await page.getByRole('option', { name: 'Destroyed' }).click();

  // Short timeout to allow for debouncing
  await page.waitForTimeout(200);

  await page.getByRole('button', { name: 'Submit' }).click();
  await page.getByText('Items received').waitFor();

  await loadTab(page, 'Received Stock');
  await clearTableFilters(page);

  await page
    .getByRole('textbox', { name: 'table-search-input' })
    .fill('my-batch-code');
  await page.getByRole('cell', { name: 'my-batch-code' }).first().waitFor();
});

test('Purchase Orders - Receive Virtual Items', async ({ browser }) => {
  const page = await doCachedLogin(browser, {
    url: 'purchasing/purchase-order/19'
  });

  // Duplicate this order
  await page.getByRole('button', { name: 'action-menu-order-actions' }).click();
  await page.getByRole('menuitem', { name: 'Duplicate' }).click();
  await page.getByRole('button', { name: 'Submit' }).click();
  await page.getByRole('tab', { name: 'Order Details' }).waitFor();

  // Issue the new order
  await page.getByRole('button', { name: 'Issue Order' }).click();
  await page.getByRole('button', { name: 'Submit' }).click();

  // Receive the line item
  await loadTab(page, 'Line Items');
  await page.getByRole('cell', { name: 'Thumbnail CRM license' }).waitFor();

  await page.getByRole('checkbox', { name: 'Select all records' }).click();
  await page
    .getByRole('button', { name: 'action-button-receive-items' })
    .click();

  await page.getByLabel('tree-field-location').fill('factory');
  await page.getByText('Factory', { exact: true }).click();

  await page.getByRole('button', { name: 'Submit' }).click();

  // 1/1 items received
  await page.getByText('1 / 1', { exact: true }).waitFor();
});

test('Purchase Orders - Duplicate', async ({ browser }) => {
  const page = await doCachedLogin(browser, {
    url: 'purchasing/purchase-order/13/detail'
  });

  await openDetailAction(page, 'order', 'duplicate');

  // Ensure a new reference is suggested
  await expect(
    page.getByLabel('text-field-reference', { exact: true })
  ).not.toBeEmpty();

  // Submit the duplicate request and ensure it completes
  await page.getByRole('button', { name: 'Submit' }).isEnabled();
  await page.getByRole('button', { name: 'Submit' }).click();
  await page.getByRole('tab', { name: 'Order Details' }).waitFor();
  await page.getByRole('tab', { name: 'Order Details' }).click();

  await page.getByText('Pending').first().waitFor();
});
