import { createApi } from './api';
/** Unit tests for form validation, rendering, etc */
import { expect, test } from './baseFixtures';
import { stevenuser } from './defaults';
import { clickOnRowMenu, loadTab, navigate, openDetailAction } from './helpers';
import { doCachedLogin } from './login';

// Test hover form action in related fields
test('Forms - Hover', async ({ browser }) => {
  const page = await doCachedLogin(browser, {
    user: stevenuser,
    url: 'purchasing/index/purchaseorders'
  });

  // Patch user settings to ensure we can see "extra model info" on hover
  const api = await createApi({
    username: stevenuser.username,
    password: stevenuser.testcred
  });

  const response = await api.patch('settings/user/SHOW_EXTRA_MODEL_INFO/', {
    data: {
      value: 'true'
    }
  });

  expect(response.status()).toBe(200);

  await page
    .getByRole('button', { name: 'action-button-add-purchase-' })
    .click();
  await page.getByLabel('related-field-supplier').fill('mou');
  await page.waitForLoadState('networkidle');
  await page.waitForTimeout(250);
  await page.getByText('Mouser Electronics').first().hover();

  // Check for hover info
  await page.getByText('Company[ID: 2]').waitFor();
  await page.getByRole('link', { name: 'View details' }).waitFor();
});

test('Forms - Stock Item Validation', async ({ browser }) => {
  const page = await doCachedLogin(browser, {
    user: stevenuser,
    url: 'stock/location/index/stock-items'
  });

  await page.waitForURL('**/web/stock/location/**');

  // Create new stock item form
  await page.getByLabel('action-button-add-stock-item').click();
  await page.getByRole('button', { name: 'Submit' }).click();

  // Check for validation errors
  await page.getByText('Form Error').waitFor();
  await page.getByText('Errors exist for one or more form fields').waitFor();
  await page.getByText('Valid part must be supplied').waitFor();

  // Adjust other field - the errors should persist
  await page.getByLabel('text-field-batch', { exact: true }).fill('BATCH-123');
  await page.waitForTimeout(250);

  await page.getByText('Valid part must be supplied').waitFor();

  // Fill out fields
  await page.getByLabel('number-field-quantity').fill('-1');
  await page.getByLabel('related-field-part').click();
  await page.getByRole('option', { name: /1551AGY/ }).click();
  await page.getByRole('button', { name: 'Submit' }).click();

  // Check for validation errors
  await page.getByText('Errors exist for one or more form fields').waitFor();
  await page
    .getByText(/Ensure this value is greater than or equal to 0/)
    .first()
    .waitFor();

  // Set location
  await page.getByLabel('tree-field-location').fill('production');
  await page.getByText('Electronics production facility').click();

  // Create the stock item
  await page.getByLabel('number-field-quantity').fill('123');
  await page.getByRole('button', { name: 'Submit' }).click();

  // Edit the resulting stock item
  await openDetailAction(page, 'stock-item', 'edit');

  await page.getByLabel('number-field-purchase_price').fill('-1');

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

  await page.getByText('Errors exist for one or more form fields').waitFor();
  await page
    .getByText('Ensure this value is greater than or equal to 0')
    .waitFor();

  // Check the error message still persists after editing a different field
  await page.getByLabel('text-field-packaging', { exact: true }).fill('a box');
  await page.waitForTimeout(250);
  await page
    .getByText('Ensure this value is greater than or equal to 0')
    .waitFor();

  // Correct the price
  await page.getByLabel('number-field-purchase_price').fill('1.2345');
  await page.getByRole('button', { name: 'Submit' }).click();
  await page.getByText('Item Updated').waitFor();

  // Ensure the stock item has been updated correctly
  await page.getByText('$151.8435').waitFor();
  await page.getByText('$151.8435').waitFor();
  await page.getByText('a box').waitFor();
  await page.getByRole('cell', { name: 'Electronics Lab' }).waitFor();
});

test('Forms - Supplier Validation', async ({ browser }) => {
  const page = await doCachedLogin(browser, {
    user: stevenuser,
    url: 'purchasing/index/suppliers'
  });
  await page.waitForURL('**/purchasing/index/**');

  await page.getByLabel('action-button-add-company').click();
  await page
    .getByLabel('text-field-website', { exact: true })
    .fill('not-a-website');

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

  // Check for validation errors
  await page.getByText('Form Error').waitFor();
  await page.getByText('Errors exist for one or more').waitFor();
  await page.getByText('This field is required').waitFor();
  await page.getByText('Enter a valid URL.').waitFor();

  // Fill out another field, expect that the errors persist
  await page
    .getByLabel('text-field-description', { exact: true })
    .fill('A description');
  await page.waitForTimeout(250);
  await page.getByText('This field is required').waitFor();
  await page.getByText('Enter a valid URL.').waitFor();

  // Generate a unique supplier name
  const supplierName = `Supplier ${new Date().getTime()}`;

  // Fill with good data
  await page
    .getByLabel('text-field-website', { exact: true })
    .fill('https://www.test-website.co.uk');
  await page.getByLabel('text-field-name', { exact: true }).fill(supplierName);
  await page.getByRole('button', { name: 'Submit' }).click();

  await page.getByText('A description').first().waitFor();
  await page
    .getByRole('link', { name: 'https://www.test-website.co.uk' })
    .waitFor();

  // Now, try to create another new supplier with the same name
  await navigate(page, 'purchasing/index/suppliers');
  await page.waitForURL('**/purchasing/index/**');
  await page.getByLabel('action-button-add-company').click();
  await page.getByLabel('text-field-name', { exact: true }).fill(supplierName);
  await page.getByRole('button', { name: 'Submit' }).click();

  // Is prevented, due to uniqueness requirements
  await page.getByText('Form Error').waitFor();
  await page.getByRole('button', { name: 'Cancel' }).click();
});

test('Forms - Keep form open option', async ({ browser }) => {
  const page = await doCachedLogin(browser, {
    user: stevenuser,
    url: 'stock/location/index/sublocations'
  });
  await page.waitForURL('**/stock/location/index/**');

  await page.getByLabel('action-button-add-stock-location').click();

  // Generate unique location name
  const locationName = `New Sublocation ${new Date().getTime()}`;

  await page.getByLabel('text-field-name', { exact: true }).fill(locationName);

  // Check keep form open switch and submit
  await page.getByRole('switch', { name: 'Keep form open' }).click();
  await page.getByRole('button', { name: 'Submit' }).click();

  // Location should be created, form should remain opened
  await page.getByText('Item Created').waitFor();
  await expect(page.getByRole('dialog')).toBeVisible();

  // Create another location and uncheck this option
  await page
    .getByLabel('text-field-name', { exact: true })
    .fill(`Another ${locationName}`);
  await page.getByRole('switch', { name: 'Keep form open' }).click();
  await page.getByRole('button', { name: 'Submit' }).click();

  // Location should be created, and the form (modal) should disappear
  await page.getByText('Item Created').waitFor();
  await expect(page.getByRole('dialog')).toBeHidden();
});

test('Forms - DateTime Field', async ({ browser }) => {
  // The "started_datetime" / "finished_datetime" test-result fields are only
  // shown when the "TEST_STATION_DATA" global setting is enabled
  const api = await createApi({});
  const settingUrl = 'settings/global/TEST_STATION_DATA/';

  const enableResponse = await api.patch(settingUrl, {
    data: { value: 'true' }
  });
  expect(enableResponse.status()).toBe(200);

  const page = await doCachedLogin(browser, {
    user: stevenuser,
    url: 'stock/item/1194/test_results'
  });
  await page.waitForURL('**/web/stock/**');
  await loadTab(page, 'Test Results');

  const cell = page.getByText('395c6d5586e5fb656901d047be27e1f7');
  await clickOnRowMenu(cell);
  await page.getByRole('menuitem', { name: 'Edit' }).click();

  // Set a value via the Mantine DateTimePicker popup - a button which opens a
  // calendar (for the date) plus separate hour/minute/second spinbuttons
  const setDateTime = async (
    fieldLabel: string,
    day: string,
    hour: string,
    minute: string
  ) => {
    const field = page.getByLabel(fieldLabel).first();
    await expect(field).toBeVisible();
    await field.click();
    await page.getByRole('button', { name: day }).first().click();

    const spinbuttons = page.getByRole('spinbutton');
    await spinbuttons.nth(0).fill(hour);
    await spinbuttons.nth(1).fill(minute);
    await spinbuttons.nth(2).fill('00');

    await page.keyboard.press('Escape');
  };

  await setDateTime(
    'date-time-field-started_datetime',
    '10 March 2024',
    '10',
    '30'
  );
  await setDateTime(
    'date-time-field-finished_datetime',
    '11 March 2024',
    '11',
    '45'
  );

  await expect(page.getByLabel('date-time-field-started_datetime')).toHaveText(
    '2024-03-10 10:30:00'
  );
  await expect(page.getByLabel('date-time-field-finished_datetime')).toHaveText(
    '2024-03-11 11:45:00'
  );

  await page.getByRole('button', { name: 'Submit' }).click();
  await page.getByText('Test result updated').waitFor();

  // Restore the global setting to its default value
  const disableResponse = await api.patch(settingUrl, {
    data: { value: 'false' }
  });
  expect(disableResponse.status()).toBe(200);
});

// Test the "nested object" field type, via the "Initial Supplier" section
// of the "Create Part" form
test('Forms - Nested Object Field', async ({ browser }) => {
  const page = await doCachedLogin(browser, {
    user: stevenuser,
    url: 'part/category/index/parts'
  });
  await page.waitForURL('**/part/category/index/**');

  await page.getByRole('button', { name: 'action-menu-add-parts' }).click();
  await page
    .getByRole('menuitem', { name: 'action-menu-add-parts-create-part' })
    .click();

  // Generate a unique part name
  const partName = `Test Part ${new Date().getTime()}`;
  await page.getByLabel('text-field-name', { exact: true }).fill(partName);

  // The "Initial Supplier" nested-object field should be visible and expanded by default
  await page.getByText('Supplier Information').waitFor();

  const supplierField = page.getByLabel(
    'related-field-initial_supplier.supplier'
  );
  await expect(supplierField).toBeVisible();
  await supplierField.fill('Mouser');
  await page.getByText('Mouser Electronics').first().click();

  const skuValue = `SKU-${new Date().getTime()}`;
  await page
    .getByLabel('text-field-initial_supplier.sku', { exact: true })
    .fill(skuValue);

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

  // Confirm the part was created with the expected name
  await page.getByText(partName).first().waitFor();
});
