import { BusinessPage } from "../../pom/business/business.page";
import { LoginPage } from "../../pom/login.page";
import { test, expect } from "../../fixtures/index";
import { randomDate, sortArrayAsc } from '../../pom/utils/utlisFunc';
import { Locator, TestInfo } from "@playwright/test";
import { randomString, randomText } from "../../utils/array";
import path from "path";

test.describe("Verify function for business tests", async () => {
  let loginPage: LoginPage;
  let businessPage: BusinessPage;

  test.beforeEach(async ({ page, conf }) => {
    loginPage = new LoginPage(page);
    businessPage = new BusinessPage(page);
    await loginPage.open();
    await loginPage.login(conf.data.username, conf.data.password);
    await businessPage.open();
  });
  test("BUSINESS_004 - Verify show entries per page", {
    tag: ["@BUSINESS_004", "@business", "@function"],
  }, async ({ }) => {
    await businessPage.dashboardLoc.table.tabInTable("All").click();
    await businessPage.showEntries(30);
    await businessPage.page.waitForTimeout(2000);
    const businessCount = await businessPage.getTotalEntries("contacts?return_type=json&per_page=10&page=1");

    await businessPage.showEntries(10);
    await businessPage.page.waitForTimeout(2000);
    const resultMessage1 = await businessPage.page
      .locator(`//p[@class="m-0 text-muted f-14 cl-gray info"]`)
      .innerText();
    const expectedMessage1 = `Showing 1 to 10 of ${businessCount} entries`;
    expect(resultMessage1).toContain(expectedMessage1);

    await businessPage.showEntries(20);
    await businessPage.page.waitForTimeout(2000);
    const resultMessage2 = await businessPage.page
      .locator(`//p[@class="m-0 text-muted f-14 cl-gray info"]`)
      .innerText();
    const expectedMessage2 = `Showing 1 to 20 of ${businessCount} entries`;
    expect(resultMessage2).toContain(expectedMessage2);
  }
  );

  test("BUSINESS_003 - Verify feature Search",
    {
      tag: ["@BUSINESS_003", "@business", "@function"],
    },
    async ({ conf }) => {
      for (const [key, value] of Object.entries(conf.data.search_data as Record<string, any>)) {
        await test.step(`Search with invalid ${key}`, async () => {
          await businessPage.search(value.invalid_data);
          await expect(businessPage.dashboardLoc.table.noResult).toBeVisible();
        });
      }

      for (const [key, value] of Object.entries(conf.data.search_data as Record<string, any>)) {
        await test.step(`Search with valid ${key}`, async () => {
          await businessPage.search(value.valid_data);
          if (key === 'business_phone') {
            await expect(businessPage.dashboardLoc.table.itemInRow(value.invalid_data).first()).toBeVisible();
          } else if (key === 'business_alias') {
            await expect(businessPage.dashboardLoc.table.itemInRow("New Business To For Test Alias").first()).toBeVisible();
          } else {
            await expect(businessPage.dashboardLoc.table.itemInRow(value.valid_data).first()).toBeVisible();
          }
        });
      }
    }
  );

  test('BUSINESS_005 - Verify feature sort business', {
    tag: ['@BUSINESS_005', '@business', '@function']
  }, async () => {

    const displayNames = ['Business Name', 'Phone', 'Email'];
    const sortedFieldName = ['name', 'phone_number', 'email_address']
    const propertyNames = ['name', 'phone_number', 'email_address'];
    const directions = ['asc', 'asc', 'asc'];

    for (let i = 0; i < displayNames.length; i++) {
      await test.step(`Sort by ${displayNames[i]} - ${directions[i]}`, async () => {
        await expect(businessPage.dashboardLoc.table.headingColumn(displayNames[i])).toBeVisible();
        await businessPage.dashboardLoc.table.headingColumn(displayNames[i]).click();
        await expect(businessPage.page).toHaveURL(
          new RegExp(`.*sort=${sortedFieldName[i]}&direction=${directions[i]}`)
        );

        let apiDataUrl = `api/v1/contacts?return_type=json&sort=${propertyNames[i]}&direction=${directions[i]}`;
        const data = await businessPage.getDataInTable(displayNames[i], propertyNames[i], apiDataUrl);
        const dataUI = sortArrayAsc(data.dataUI);
        console.log(`Sort by: ${displayNames[i]}, direction: ${directions[i]}, property: ${propertyNames[i]}`);
        expect(data.dataApi).toEqual(dataUI);
      });
    }
  });

  test('BUSINESS_006 - Verify feature filter business', {
    tag: ['@BUSINESS_006', '@business', '@feature']
  }, async ({ conf }) => {
    const filterFields = businessPage.businessProps.filterProperties;
    for (let i = 0; i < filterFields.length; i++) {
      // clear filter
      await businessPage.open();

      // prepare locator
      let fieldLocator: Locator;
      switch (filterFields[i].type) {
        case 'input':
          fieldLocator = businessPage.dashboardLoc.search.filter.popup.inputField(filterFields[i].name);
          break;
        default:
          throw new Error(`Unsupported filter type: ${filterFields[i].type}`);
      }

      // Fill invalid value
      if (filterFields[i].name !== 'business_type_id') {
        await businessPage.dashboardLoc.search.filter.btn.click();
        await expect(businessPage.dashboardLoc.search.filter.popup.container).toBeVisible();
        await fieldLocator.fill(conf.data.filter_data[filterFields[i].name].invalid_data);
        await businessPage.dashboardLoc.search.filter.popup.btnApply.click();
        await expect(businessPage.dashboardLoc.table.noResult).toBeVisible();
      }

      // Fill valid value
      await businessPage.dashboardLoc.search.filter.btn.click();
      await expect(businessPage.dashboardLoc.search.filter.popup.container).toBeVisible();
      if (filterFields[i].name !== 'business_type_id') {
        await fieldLocator.fill(conf.data.filter_data[filterFields[i].name].valid_data);
      } else {
        await fieldLocator.click();
        await expect(businessPage.businessLoc.optionBusinessType("Urgent Care")).toBeVisible();
        await businessPage.businessLoc.optionBusinessType("Urgent Care").click();
      }
      await businessPage.dashboardLoc.search.filter.popup.btnApply.click();
      const dataFilterFields = await businessPage.filterSingleField("contacts", filterFields[i].name, conf.data.filter_data[filterFields[i].name].valid_data, filterFields[i].paramFilter);
      expect(dataFilterFields.every(item => item === conf.data.filter_data[filterFields[i].name].valid_data)).toBeTruthy();
      await expect(businessPage.dashboardLoc.table.noResult).not.toBeVisible();
    }
  });

  test('BUSINESS_007 - Verify feature Pin', {
    tag: ['@BUSINESS_007', '@business', '@feature']
  }, async ({ conf }) => {
    await test.step('Search and verify icon Pin visible', async () => {
      //Search
      await businessPage.businessLoc.inputSearch.fill(conf.data.business_name);
      await expect(businessPage.dashboardLoc.table.headingColumn('Pin')).toBeVisible();

      //verify icon Pin visible
      await expect(businessPage.businessLoc.pinIcon(conf.data.business_name)).toBeVisible()
    });

    await test.step('Verify Pin and unpin feature', async () => {
      //Click Pin icon and verify
      await businessPage.businessLoc.pinIcon(conf.data.business_name).click();
      await expect(businessPage.businessLoc.pinnedIcon(conf.data.business_name)).toBeVisible();
      await expect(businessPage.businessLoc.firstBusiness(conf.data.business_id)).toBeVisible();

      // Click unpin
      await businessPage.businessLoc.pinnedIcon(conf.data.business_name).click()
      await expect(businessPage.businessLoc.pinIcon(conf.data.business_name)).toBeVisible();

    });
  });

  test('BUSINESS_008 - Verify feature customized columns', {
    tag: ['@BUSINESS_008', '@business', '@ui']
  }, async () => {
    const customThreeDotLocator = businessPage.genLoc("//div[contains(@class, 'dropdown d-flex align-items-center')]");
    // Verify default columns displayed
    await test.step("Verify default columns displayed", async () => {
      const customizedColumns = businessPage.businessProps.customizedColumns;
      for (let i = 0; i < customizedColumns.length; i++) {
        if (customizedColumns[i].default) {
          await expect(businessPage.dashboardLoc.listing.heading.headingColumn(customizedColumns[i].tableDisplayName)).toBeVisible();
        }
      }
    });

    // Verify customized column show disable items and active items
    await test.step("Verify customized columns popup state", async () => {
      await businessPage.openThreedotMenu(businessPage.businessProps.threeDotDropdownMenus.customizedColumn, customThreeDotLocator);

      // Verify enabled column and disabled column
      const customizedColumns = businessPage.businessProps.customizedColumns;
      for (let i = 0; i < customizedColumns.length; i++) {
        if (customizedColumns[i].default) {
          await expect(businessPage.dashboardLoc.listing.popup.customizedColumn.columnCheckbox(customizedColumns[i].name)).toBeDisabled();
        } else {
          await expect(businessPage.dashboardLoc.listing.popup.customizedColumn.columnCheckbox(customizedColumns[i].name)).toBeEnabled();
        }
      }
    });

    // Pre-condition: disable all enabled column
    await test.step("Pre-condition: disable all enabled column", async () => {
      const customizedColumns = businessPage.businessProps.customizedColumns;
      for (let i = 0; i < customizedColumns.length; i++) {
        if (!customizedColumns[i].default) {
          await businessPage.dashboardLoc.listing.popup.customizedColumn.columnCheckbox(customizedColumns[i].name).setChecked(false);
        }
      }
      await businessPage.dashboardLoc.listing.popup.customizedColumn.btnApply.click();
    });

    // Check each columns and verify it shown
    await test.step("Check each columns and verify it shown", async () => {
      await businessPage.open();
      const customizedColumns = businessPage.businessProps.customizedColumns.filter(column => !column.default);
      for (let i = 0; i < customizedColumns.length; i++) {
        await businessPage.openThreedotMenu(businessPage.businessProps.threeDotDropdownMenus.customizedColumn, customThreeDotLocator);
        await businessPage.dashboardLoc.listing.popup.customizedColumn.columnCheckbox(customizedColumns[i].name).setChecked(true);
        await businessPage.dashboardLoc.listing.popup.customizedColumn.btnApply.click();
        await expect(businessPage.dashboardLoc.listing.heading.headingColumn(customizedColumns[i].tableDisplayName)).toBeVisible();
      }
    });

    // Uncheck each columns and verify it hidden
    await test.step("Uncheck each columns and verify it hidden", async () => {
      await businessPage.open();
      const customizedColumns = businessPage.businessProps.customizedColumns.filter(column => !column.default);
      for (let i = 0; i < customizedColumns.length; i++) {
        await businessPage.openThreedotMenu(businessPage.businessProps.threeDotDropdownMenus.customizedColumn, customThreeDotLocator);
        await businessPage.dashboardLoc.listing.popup.customizedColumn.columnCheckbox(customizedColumns[i].name).setChecked(false);
        await businessPage.dashboardLoc.listing.popup.customizedColumn.btnApply.click();
        await expect(businessPage.dashboardLoc.listing.heading.headingColumn(customizedColumns[i].tableDisplayName)).not.toBeVisible();
      }
    });
  });

  test("BUSINESS_013 - Verify business creation validation", {
    tag: ['@BUSINESS_013', '@business', '@function']
  }, async ({ conf }) => {
    await test.step("Verify required field validation - business name", async () => {
      await businessPage.dashboardLoc.buttonByText("New Business").click();
      await expect(businessPage.dashboardLoc.modal.headerModal('New Business')).toBeVisible();
      await businessPage.dashboardLoc.buttonByText("Create").click();
      await expect(businessPage.dashboardLoc.modal.errorMessage("The business name is required.")).toBeVisible();
    });

    await test.step("Verify email format validation", async () => {
      const emailInput = businessPage.dashboardLoc.modal.inputByID("input_email_address");

      await emailInput.fill(conf.data.invalid_email);
      await businessPage.dashboardLoc.buttonByText("Create").click();

      await expect(businessPage.dashboardLoc.modal.errorMessageSpan("The email address field is not in the correct format")).toBeVisible();
      await emailInput.clear();
    });

    await test.step("Verify duplicate business name validation", async () => {
      await businessPage.dashboardLoc.modal.inputByID("autocomplete_name").first().fill(conf.data.exist_bussiness);
      await businessPage.waitForSecond(2);
      await businessPage.dashboardLoc.modal.headerModal("New Business").click();
      await businessPage.dashboardLoc.buttonByText("Create").click();

      await expect(businessPage.dashboardLoc.modal.duplicateErrMsg).toBeVisible();

      await businessPage.businessLoc.create.btnCloseModal.click();
      await businessPage.dashboardLoc.buttonByText("Leave").click();
    });

    await test.step("Verify character limit validation for all fields", async () => {
      await businessPage.dashboardLoc.buttonByText("New Business").click();
      await expect(businessPage.dashboardLoc.modal.headerModal('New Business')).toBeVisible();

      const inputFields = businessPage.inputCreateBusiness;

      for (const fieldConfig of inputFields) {
        const fieldInput = businessPage.dashboardLoc.modal.inputByID(fieldConfig.id).nth(fieldConfig.child);
        await fieldInput.fill(conf.data.exceed_word);
        await expect(fieldInput).toHaveValue(conf.data.exceed_word);
      }

      await businessPage.dashboardLoc.buttonByText("Create").click();

      for (const fieldConfig of inputFields) {
        const expectedErrorMsg = `The ${fieldConfig.name} field must not be greater than ${fieldConfig.maxExceed} characters.`;

        if (fieldConfig.name === "name") {
          await expect(businessPage.dashboardLoc.modal.errorMessage(expectedErrorMsg)).toBeVisible();
        } else {
          await expect(businessPage.dashboardLoc.modal.errorMessageSpan(expectedErrorMsg)).toBeVisible();
        }
      }
    });
  })

  test("BUSINESS_014 - Verify successful business creation", {
    tag: ['@BUSINESS_014', '@business', '@function']
  }, async ({ conf }) => {
    let createdBusinessName: string = "";
    const createFormData = conf.data.input_create;

    await test.step("Create business without create another option", async () => {
      await businessPage.dashboardLoc.buttonByText("New Business").click();
      await expect(businessPage.dashboardLoc.modal.headerModal('New Business')).toBeVisible();

      await test.step("Fill business creation form", async () => {
        for (const fieldConfig of createFormData) {
          const fieldInput = businessPage.dashboardLoc.modal.inputByID(fieldConfig.input_field).nth(fieldConfig.child);

          switch (fieldConfig.type) {
            case "input":
              if (fieldConfig.input_field === "autocomplete_name") {
                createdBusinessName = fieldConfig.value + randomText(8) + randomString(4);
                await fieldInput.fill(createdBusinessName);
                await expect(fieldInput).toHaveValue(createdBusinessName);
              } else {
                await fieldInput.fill(fieldConfig.value);
                await expect(fieldInput).toHaveValue(fieldConfig.value);
              }
              break;

            case "select":
              await fieldInput.fill(fieldConfig.value);
              await expect(businessPage.businessLoc.create.optionDropdown(fieldConfig.value)).toBeVisible();
              await businessPage.businessLoc.create.optionDropdown(fieldConfig.value).click();
              break;

            default:
              console.log(`Unknown field type: ${fieldConfig.type} for ${fieldConfig.input_field}`);
          }
        }
      });

      await test.step("Submit business creation", async () => {
        await businessPage.dashboardLoc.modal.headerModal("New Business").click();
        await businessPage.dashboardLoc.buttonByText("Create").click();

        await expect(businessPage.dashboardLoc.msgCreateSuccess.first()).toBeVisible();
        await expect(businessPage.dashboardLoc.modal.headerModal("New Business")).not.toBeVisible();
      });
    });

    await test.step("Verify created business data persistence", async () => {
      await businessPage.getDetailCase(createdBusinessName);
      await businessPage.dashboardLoc.buttonByText("Update").first().click();
      await expect(businessPage.dashboardLoc.modal.headerModal("Business Detail")).toBeVisible();

      for (const fieldConfig of createFormData) {
        if (fieldConfig.input_field === "autocomplete_name") {
          await expect(businessPage.dashboardLoc.modal.inputByID(fieldConfig.input_field).nth(fieldConfig.child)).toHaveValue(createdBusinessName);
        } else if (fieldConfig.input_field === "multi_select_tags") {
          await expect(businessPage.businessLoc.create.tag(fieldConfig.value)).toBeVisible();
        } else {
          await expect(businessPage.dashboardLoc.modal.inputByID(fieldConfig.input_field).first()).toHaveValue(fieldConfig.value);
        }
      }
    });

    await test.step("Verify business creation with create another option", async () => {
      const anotherBusinessName = `Business${randomString(6)}`;

      await businessPage.open();
      await businessPage.dashboardLoc.buttonByText("New Business").click();
      await expect(businessPage.dashboardLoc.modal.headerModal('New Business')).toBeVisible();

      await businessPage.dashboardLoc.modal.inputByID("autocomplete_name").first().fill(anotherBusinessName);
      await businessPage.businessLoc.create.checkboxCreateAnother.check();
      await businessPage.dashboardLoc.buttonByText("Create").click();

      await expect(businessPage.dashboardLoc.msgCreateSuccess.first()).toBeVisible();
      await expect(businessPage.dashboardLoc.modal.headerModal("New Business")).toBeVisible();
    });
  })

  test("BUSINESS_015 - Verify add tag in business's detail", {
    tag: ['@BUSINESS_015', '@business', '@function']
  }, async ({ conf }) => {
    await test.step("Navigate to business detail", async () => {
      await businessPage.getDetailCase(conf.data.business_name);
    });

    await test.step("Verify add tags with tag count greater than 9 (invalid)", async () => {
      await businessPage.addMultipleTags(10);
      await businessPage.saveTags();
      await expect(businessPage.dashboardLoc.tag.errorMaxTag).toBeVisible();
    });

    await test.step("Verify when add < 9 tag (valid)", async () => {
      await businessPage.removeOneTag();
      await businessPage.saveTags();
      await expect(businessPage.dashboardLoc.msgSuccess.first()).toBeVisible();
      await businessPage.dashboardLoc.btnClosePopupNotification.click();
      await expect(businessPage.dashboardLoc.tag.btnSaveTag).not.toBeVisible();

      const tagCount = await businessPage.getTagCount();
      expect(tagCount).toBe(9);
    });

    await test.step("Clear all tag", async () => {
      await businessPage.clearAllTags();
      await businessPage.saveTags();
      await expect(businessPage.dashboardLoc.msgSuccess).toBeVisible();
      await businessPage.waitForSecond(1);
      await businessPage.dashboardLoc.btnClosePopupNotification.click();
      await expect(businessPage.dashboardLoc.tag.btnSaveTag).not.toBeVisible();

      const tagCount = await businessPage.getTagCount();
      expect(tagCount).toBe(0);
    });
  });

  test("BUSINESS_017 - Verify when click add new contact and add new case", {
    tag: ['@BUSINESS_017', '@business_update', '@function']
  }, async ({ conf }) => {
    await test.step("Verify when click add new contact", async () => {
      await businessPage.getDetailCase(conf.data.business_name);
      await expect(businessPage.dashboardLoc.detail.tabName("Contacts")).toBeVisible();
      await businessPage.waitForSecond(1.5);
      await businessPage.dashboardLoc.detail.tabName("Contacts").click({ force: true });
      await businessPage.businessLoc.detail.threeDotsBtn.click();
      await businessPage.businessLoc.detail.dropdownOption("Add new Contact").click();

      await expect(businessPage.dashboardLoc.modal.headerModal("New Contact")).toBeVisible();
      await expect(businessPage.dashboardLoc.root).toMatchAriaSnapshot(businessPage.businessSnapshot.businessCreateNewContactModal);
    });

    await test.step("Verify when click add new case", async () => {
      await businessPage.businessLoc.create.btnCloseModalContact.click();
      await expect(businessPage.dashboardLoc.modal.headerModal("New Contact")).not.toBeVisible();
      await businessPage.dashboardLoc.detail.tabName("Cases").click();
      await businessPage.waitForSecond(1);
      await businessPage.businessLoc.detail.threeDotsBtn.click();
      await businessPage.businessLoc.detail.dropdownOption("Add new Case").click();

      await expect(businessPage.dashboardLoc.common.spanText("New Case")).toBeVisible();
      await expect(businessPage.businessLoc.create.tag(conf.data.business_name)).toBeVisible();
    });
  });

  test("BUSINESS_018 - Verify list Bulk Edit", {
    tag: ['@BUSINESS_018', '@business', '@function']
  }, async ({ conf }) => {
    // Initialize
    await businessPage.getDetailCase(conf.data.business_name);

    // Test scenarios
    await businessPage.verifyBulkEditForTab("Contacts", 3, "Business Detail");
    await businessPage.verifyBulkEditForTab("Contacts", 5, "Business Detail");
    await businessPage.verifyBulkEditForTab("Cases", 3, "Business Detail");
    await businessPage.verifyBulkEditForTab("Cases", 5, "Business Detail", false);
  });

  test("BUSINESS_025 - Change work type", {
    tag: ['@BUSINESS_025', '@business', '@function']
  }, async ({ conf }) => {
    let totalActiveEntries: number = 0;
    let totalReferenceEntries: number = 0;

    await test.step("Change business to referrence", async () => {
      // Get total Entries
      totalActiveEntries = await businessPage.getTotalEntriesByTabs("contacts", "0,1", false);
      totalReferenceEntries = await businessPage.getTotalEntriesByTabs("contacts", "2", false);

      await businessPage.getDetailCase(conf.data.business_name);
      await expect(businessPage.dashboardLoc.detail.workType("Active")).toBeVisible();

      // Change work type to reference
      await businessPage.dashboardLoc.detail.workType("Active").click();
      await expect(businessPage.dashboardLoc.detail.optionWorkType("Reference")).toBeVisible();
      await businessPage.dashboardLoc.detail.optionWorkType("Reference").click();
      await expect(businessPage.dashboardLoc.detail.workType("Reference")).toBeVisible();
    });

    await test.step("Verify business in list business", async () => {
      await businessPage.open();

      //Veriy total entries changed
      expect(totalActiveEntries - 1).toBe(await businessPage.getTotalEntriesByTabs("contacts", "0,1", false));
      expect(totalReferenceEntries + 1).toBe(await businessPage.getTotalEntriesByTabs("contacts", "2", false));

      //Veriy in tab Active
      await businessPage.dashboardLoc.table.tabInTable("Active").click();
      await businessPage.search(conf.data.business_name);
      await expect(businessPage.dashboardLoc.table.itemInRow(conf.data.business_name)).not.toBeVisible();

      //Verify in tab Reference
      await businessPage.dashboardLoc.table.tabInTable("Reference").click();
      await businessPage.search(conf.data.business_name);
      await expect(businessPage.dashboardLoc.table.itemInRow(conf.data.business_name)).toBeVisible();
    });

    await test.step("Change business back to active", async () => {
      await businessPage.dashboardLoc.table.itemInRow(conf.data.business_name).click();
      await expect(businessPage.dashboardLoc.detail.workType("Reference")).toBeVisible();
      // Change work type to active
      await businessPage.dashboardLoc.detail.workType("Reference").click();
      await expect(businessPage.dashboardLoc.detail.optionWorkType("Active")).toBeVisible();
      await businessPage.dashboardLoc.detail.optionWorkType("Active").click();
      await expect(businessPage.dashboardLoc.detail.workType("Active")).toBeVisible();
    });

    await test.step("Verify business back to active in list business", async () => {
      await businessPage.open();

      //Verify total entries changed
      expect(totalActiveEntries).toBe(await businessPage.getTotalEntriesByTabs("contacts", "0,1", false));
      expect(totalReferenceEntries).toBe(await businessPage.getTotalEntriesByTabs("contacts", "2", false));

      //Veriy in tab Active
      await businessPage.dashboardLoc.table.tabInTable("Active").click();
      await businessPage.search(conf.data.business_name);
      await expect(businessPage.dashboardLoc.table.itemInRow(conf.data.business_name)).toBeVisible();

      //Verify in tab Reference
      await businessPage.dashboardLoc.table.tabInTable("Reference").click();
      await businessPage.search(conf.data.business_name);
      await expect(businessPage.dashboardLoc.table.itemInRow(conf.data.business_name)).not.toBeVisible();
    });
  });

  test("BUSINESS_026 - Verify tab view all ", {
    tag: ['@BUSINESS_026', '@business', '@function']
  }, async ({ conf }) => {
    const tabs = [
      { name: "All", types: "0,1,2" },
      { name: "Active", types: "0,1" },
      { name: "Reference", types: "2" }
    ];
    let totalBeforeSearch: number = 0;
    let totalAfterSearch: number = 0;
    await test.step("Verify total in tab", async () => {
      // Fetch all API totals
      const apiTotals = await Promise.all(
        tabs.map(tab => businessPage.getTotalEntriesByTabs("contacts", tab.types, false))
      );
      expect(apiTotals[0]).toBe(apiTotals[1] + apiTotals[2]);

      // Fetch UI totals
      await businessPage.waitAllRequestCompeleted();
      const uiTotals = await Promise.all(
        tabs.map(tab => businessPage.dashboardLoc.common.spanCountByTab(tab.name).innerText().then(Number))
      );
      expect(uiTotals[0]).toBe(uiTotals[1] + uiTotals[2]);
      totalBeforeSearch = uiTotals[0];
      // Verify each tab shows correct total in table and compare API vs UI
      for (let i = 0; i < tabs.length; i++) {
        await businessPage.dashboardLoc.table.tabInTable(tabs[i].name).click();
        await expect(businessPage.dashboardLoc.table.entriesTotal).toContainText(`${uiTotals[i]}`);
        expect(uiTotals[i]).toBe(apiTotals[i]);
      }
    });

    await test.step("Verify when search and change tab", async () => {
      await businessPage.search(conf.data.business_name);
      await businessPage.waitAllRequestCompeleted();

      const apiTotals = await Promise.all(
        tabs.map(tab => businessPage.getTotalEntriesByTabs("contacts", tab.types, false, "s=Business+New"))
      );
      expect(apiTotals[0]).toBe(apiTotals[1] + apiTotals[2]);

      await businessPage.waitForSecond(2); // Wait for UI to update after search

      const uiTotals = await Promise.all(
        tabs.map(tab => businessPage.dashboardLoc.common.spanCountByTab(tab.name).innerText().then(Number))
      );
      expect(uiTotals[0]).toBe(uiTotals[1] + uiTotals[2]);
      totalAfterSearch = uiTotals[0];
      expect(totalAfterSearch).toBeLessThan(totalBeforeSearch);

      // Verify each tab shows correct total in table and compare API vs UI
      for (let i = 0; i < tabs.length; i++) {
        await businessPage.dashboardLoc.table.tabInTable(tabs[i].name).click();
        await expect(businessPage.dashboardLoc.search.inputSearch).toHaveValue(conf.data.business_name);
        await expect(businessPage.dashboardLoc.table.entriesTotal).toContainText(`${uiTotals[i]}`);
        expect(uiTotals[i]).toBe(apiTotals[i]);
      }
    });
  });

  // Attachment 
  test("BUSINESS_020 - Verify Remove file", {
    tag: ['@BUSINESS_020', '@business', '@function', '@attachment']
  }, async ({ apiHelper }) => {
    const businessName = `${randomText(5)} ${randomString(6)} ${randomText(5)}`;
    const filePathValidPdf = path.resolve(__dirname, `test-files/file-pdf.pdf`);
    const filePathValidJpg = path.resolve(__dirname, `test-files/file-jpg.jpg`);

    await test.step("Preconditon: Create new business", async () => {
      await apiHelper.createBusiness({
        name: businessName
      });
    });

    await test.step("Goto business and upload 2 files", async () => {
      await businessPage.getDetailCase(businessName);
      await businessPage.dashboardLoc.detail.tabName("Attachment").click();
      await businessPage.waitForSecond(1);

      await businessPage.businessLoc.detail.inputUploadFile.setInputFiles([filePathValidPdf, filePathValidJpg]);
      await expect(businessPage.dashboardLoc.common.divText("file-pdf.pdf")).toBeVisible({ timeout: 15_000 });
      await expect(businessPage.dashboardLoc.common.divText("file-jpg.jpg")).toBeVisible({ timeout: 15_000 });
    });

    await test.step("Verify remove file in list view", async () => {
      await businessPage.switchToAttachmentLayout('list');
      await businessPage.dashboardLoc.detail.fileAttachmentRow("file-pdf.pdf").hover();
      await expect(businessPage.dashboardLoc.detail.iconRemoveFile("file-pdf.pdf")).toBeVisible();
      await businessPage.dashboardLoc.detail.iconRemoveFile("file-pdf.pdf").click();

      // Show modal confirm
      await expect(businessPage.dashboardLoc.modal.headerModalh2("Remove this file?")).toBeVisible();
      await businessPage.dashboardLoc.modal.inputByID("input_text-remove").fill("Remove");
      await expect(businessPage.dashboardLoc.buttonByText("Remove")).toBeEnabled();
      await businessPage.dashboardLoc.buttonByText("Remove").click();
      await expect(businessPage.dashboardLoc.msgRemoveAttachment).toBeVisible();
      await businessPage.dashboardLoc.btnClosePopupNotification.click();
      await expect(businessPage.dashboardLoc.common.divText("file-pdf.pdf")).not.toBeVisible();
    });

    await test.step("Verify remove file in grid view", async () => {
      await businessPage.switchToAttachmentLayout('grid');
      await businessPage.dashboardLoc.detail.buttonDotsAction.first().click();
      await businessPage.dashboardLoc.common.divText("Remove").click();

      // Show modal confirm
      await expect(businessPage.dashboardLoc.modal.headerModalh2("Remove this file?")).toBeVisible();
      await businessPage.dashboardLoc.modal.inputByID("input_text-remove").fill("Remove");
      await expect(businessPage.dashboardLoc.buttonByText("Remove")).toBeEnabled();
      await businessPage.dashboardLoc.buttonByText("Remove").click();
      await expect(businessPage.dashboardLoc.msgRemoveAttachment).toBeVisible();
      await expect(businessPage.dashboardLoc.common.divText("file-jpg.jpg")).not.toBeVisible();
    });
  });

  test("BUSINESS_021 - Verify download file", {
    tag: ['@BUSINESS_021', '@business', '@function', '@attachment']
  }, async ({ apiHelper }) => {
    const businessName = `${randomText(8)} ${randomString(5)} ${randomText(5)}`;
    const filePathValidPdf = path.resolve(__dirname, `test-files/file-pdf.pdf`);

    await test.step("Preconditon: Create new business", async () => {
      await apiHelper.createBusiness({
        name: businessName
      });
    });

    await test.step("Goto business and upload 2 files", async () => {
      await businessPage.getDetailCase(businessName);
      await businessPage.dashboardLoc.detail.tabName("Attachment").click();
      await businessPage.businessLoc.detail.inputUploadFile.setInputFiles([filePathValidPdf]);
      await expect(businessPage.dashboardLoc.common.divText("file-pdf.pdf")).toBeVisible();
    });

    await test.step("Verify download file in list view", async () => {
      await businessPage.switchToAttachmentLayout('list');
      await businessPage.dashboardLoc.detail.fileAttachmentRow("file-pdf.pdf").hover();
      await expect(businessPage.dashboardLoc.detail.iconDownloadFile("file-pdf.pdf")).toBeVisible();

      const downloadPromise = businessPage.page.waitForEvent('download');
      await businessPage.dashboardLoc.detail.iconDownloadFile("file-pdf.pdf").click();
      const download = await downloadPromise;

      const fileName = download.suggestedFilename();
      expect(fileName).toContain('file-pdf');

      const savePath = `test-results/${fileName}`;
      await download.saveAs(savePath);

      const fileContent = require('fs').readFileSync(savePath);
      expect(fileContent.length).toBeGreaterThan(0);

      require('fs').unlinkSync(savePath);
    });

    await test.step("Verify download file in grid view", async () => {
      await businessPage.switchToAttachmentLayout('grid');
      await businessPage.dashboardLoc.detail.buttonDotsAction.first().click();
      await expect(businessPage.dashboardLoc.common.aText("Download")).toBeVisible();
      const downloadPromise = businessPage.page.waitForEvent('download');
      await businessPage.dashboardLoc.common.aText("Download").click();
      const download = await downloadPromise;

      const fileName = download.suggestedFilename();
      expect(fileName).toContain('file-pdf');

      const savePath = `test-results/${fileName}`;
      await download.saveAs(savePath);

      const fileContent = require('fs').readFileSync(savePath);
      expect(fileContent.length).toBeGreaterThan(0);

      require('fs').unlinkSync(savePath);
    });
  });

  test("BUSINESS_022 - Verify Edit file name", {
    tag: ['@BUSINESS_022', '@business', '@function', '@attachment']
  }, async ({ conf, apiHelper }) => {
    const businessName = `${randomText(5)} ${randomString(5)} ${randomText(5)}`;
    const filePathValidPdf = path.resolve(__dirname, `test-files/file-pdf.pdf`);
    let newFileName: string = "file-pdf-renamed";

    await test.step("Preconditon: Create new business", async () => {
      await apiHelper.createBusiness({
        name: businessName
      });
    });

    await test.step("Goto business and upload 2 files", async () => {
      await businessPage.getDetailCase(businessName);
      await businessPage.dashboardLoc.detail.tabName("Attachment").click();
      await businessPage.businessLoc.detail.inputUploadFile.setInputFiles([filePathValidPdf]);
      await expect(businessPage.dashboardLoc.common.divText("file-pdf.pdf")).toBeVisible();
    });

    await test.step("Verify edit file name in list view", async () => {
      await businessPage.switchToAttachmentLayout('list');
      await businessPage.dashboardLoc.detail.fileAttachmentRow("file-pdf.pdf").hover();
      await expect(businessPage.dashboardLoc.detail.iconEditFileName("file-pdf.pdf")).toBeVisible();
      await businessPage.dashboardLoc.detail.iconEditFileName("file-pdf.pdf").click();

      // Verify empty file name not allow to submit
      await businessPage.dashboardLoc.modal.inputByID("input_edit-file-name").clear();
      await businessPage.dashboardLoc.detail.buttonActionEdit.nth(1).click();
      await expect(businessPage.dashboardLoc.common.spanText(conf.data.error_empty)).toBeVisible();

      // Verify edit to long file name
      await businessPage.dashboardLoc.modal.inputByID("input_edit-file-name").fill(conf.data.name_long);
      await businessPage.dashboardLoc.detail.buttonActionEdit.nth(1).click();
      await expect(businessPage.dashboardLoc.common.spanText(conf.data.error_long)).toBeVisible();

      // Verify edit file name successfully

      await businessPage.dashboardLoc.modal.inputByID("input_edit-file-name").fill(newFileName);
      await businessPage.dashboardLoc.detail.buttonActionEdit.nth(1).click();
      await expect(businessPage.dashboardLoc.msgChangeNameAttachment).toBeVisible();
      await expect(businessPage.dashboardLoc.common.divText(newFileName)).toBeVisible();
    });

    await test.step("Verify edit file name in grid view", async () => {
      await businessPage.switchToAttachmentLayout('grid');
      await businessPage.dashboardLoc.detail.fileAttachmentGrid(newFileName).hover();
      await expect(businessPage.dashboardLoc.detail.iconEditFileNameGrid(newFileName)).toBeVisible();
      await businessPage.dashboardLoc.detail.iconEditFileNameGrid(newFileName).click();
      await expect(businessPage.dashboardLoc.modal.headerModalh2("Rename")).toBeVisible();

      // Verify empty file name not allow to submit
      await businessPage.dashboardLoc.modal.inputByID("input_edit-file-name").clear();
      await businessPage.dashboardLoc.buttonByText("Ok").click();
      await expect(businessPage.dashboardLoc.common.spanText(conf.data.error_empty)).toBeVisible();

      // Verify edit to long file name
      await businessPage.dashboardLoc.modal.inputByID("input_edit-file-name").fill(conf.data.name_long);
      await businessPage.dashboardLoc.buttonByText("Ok").click();
      await expect(businessPage.dashboardLoc.common.spanText(conf.data.error_long)).toBeVisible();

      // Verify edit file name successfully
      await businessPage.dashboardLoc.modal.inputByID("input_edit-file-name").fill(newFileName);
      await businessPage.dashboardLoc.buttonByText("Ok").click();
      await expect(businessPage.dashboardLoc.msgChangeNameAttachment).toBeVisible();
      await expect(businessPage.dashboardLoc.common.divText(newFileName)).toBeVisible();
    });
  });

  test("BUSINESS_023 - Verify upload single file", {
    tag: ['@BUSINESS_023', '@business', '@function', '@attachment']
  }, async ({ conf, apiHelper }) => {
    const businessName = `${randomText(7)} ${randomString(5)} ${randomText(5)}`;
    const filePath25mb = path.resolve(__dirname, `test-files/file-25mb.png`);
    const filePathValidPdf = path.resolve(__dirname, `test-files/file-pdf.pdf`);
    const filePathInvalid = path.resolve(__dirname, `test-files/file-json.json`);

    await test.step("Preconditon: Create new business", async () => {
      await apiHelper.createBusiness({
        name: businessName
      });
    });

    await test.step("Goto business and upload file > 25mb", async () => {
      await businessPage.getDetailCase(businessName);
      await businessPage.dashboardLoc.detail.tabName("Attachment").click();

      await businessPage.businessLoc.detail.inputUploadFile.setInputFiles([filePath25mb]);
      await expect(businessPage.dashboardLoc.common.spanText(conf.data.error_25mb)).toBeVisible();
      await expect(businessPage.dashboardLoc.common.spanText(`0 upload complete`)).toBeVisible();
    });

    await test.step("Verify upload more than 50 files", async () => {
      const filesArray = Array(51).fill(filePathValidPdf);
      await businessPage.businessLoc.detail.inputUploadFile.setInputFiles(filesArray);
      await expect(businessPage.dashboardLoc.modal.headerModalh2("Warning").first()).toBeVisible();
      await expect(businessPage.dashboardLoc.common.pTextContainsAll(conf.data.error_upload_maximum_file)).toBeVisible();
      await businessPage.dashboardLoc.detail.btnCloseModalWarning(1).click();
      await expect(businessPage.dashboardLoc.modal.headerModalh2("Warning").first()).not.toBeVisible();
    });

    await test.step("Verify upload invalid file type", async () => {
      await businessPage.businessLoc.detail.inputUploadFile.setInputFiles(filePathInvalid);
      await expect(businessPage.dashboardLoc.modal.headerModalh2("Warning").nth(1)).toBeVisible();
      await expect(businessPage.dashboardLoc.common.pText(conf.data.error_invalid)).toBeVisible();
      await businessPage.dashboardLoc.detail.btnCloseModalWarning(2).click();
      await expect(businessPage.dashboardLoc.modal.headerModalh2("Warning").nth(1)).not.toBeVisible();
    });

    await test.step("Verify upload file 2 times and replace file", async () => {
      // Upload file first time
      await businessPage.businessLoc.detail.inputUploadFile.setInputFiles(filePathValidPdf);
      await expect(businessPage.dashboardLoc.common.divText("file-pdf.pdf")).toBeVisible();
      await expect(businessPage.dashboardLoc.common.spanText(`1 upload complete`)).toBeVisible();

      // Upload file second time with same name but different content
      await businessPage.businessLoc.detail.inputUploadFile.setInputFiles(filePathValidPdf);
      await expect(businessPage.dashboardLoc.common.divText("file-pdf (1).pdf")).toBeVisible();
      await expect(businessPage.dashboardLoc.common.spanText(`2 uploads complete`)).toBeVisible();
    });
  });

  test("BUSINESS_024 - Verify upload multiple files", {
    tag: ['@BUSINESS_024', '@business', '@function', '@attachment']
  }, async ({ conf, apiHelper }) => {
    const businessName = `${randomText(7)} ${randomString(5)} ${randomText(5)}`;
    const filePath25mb = path.resolve(__dirname, `test-files/file-25mb.png`);
    const filePathInvalid = path.resolve(__dirname, `test-files/file-json.json`);
    const filePathValidWord = path.resolve(__dirname, `test-files/file-doc.doc`);
    const filePathValidExcel = path.resolve(__dirname, `test-files/file-xls.xls`);
    const filePathValidPng = path.resolve(__dirname, `test-files/file-png.png`);

    await test.step("Preconditon: Create new business", async () => {
      await apiHelper.createBusiness({
        name: businessName
      });
    });

    await test.step("Goto business and upload multiples file", async () => {
      await businessPage.getDetailCase(businessName);
      await businessPage.dashboardLoc.detail.tabName("Attachment").click();

      await businessPage.businessLoc.detail.inputUploadFile.setInputFiles([filePath25mb, filePathInvalid, filePathValidWord, filePathValidExcel, filePathValidPng]);

      // Show modal warning for invalid file type
      await expect(businessPage.dashboardLoc.modal.headerModalh2("Warning").nth(1)).toBeVisible();
      await expect(businessPage.dashboardLoc.common.pText(conf.data.error_invalid)).toBeVisible();
      await businessPage.dashboardLoc.buttonByText("Skip Files").click();
      await expect(businessPage.dashboardLoc.modal.headerModalh2("Warning").nth(1)).not.toBeVisible();


      await expect(businessPage.dashboardLoc.common.spanText(`3 uploads complete`)).toBeVisible();

      // Show error message for file > 25mb
      await expect(businessPage.dashboardLoc.common.spanText(conf.data.error_25mb)).toBeVisible();

      // Show only 3 valid files in attachment list
      await expect(businessPage.dashboardLoc.common.divText("file-doc.doc")).toBeVisible();
      await expect(businessPage.dashboardLoc.common.divText("file-xls.xls")).toBeVisible();
      await expect(businessPage.dashboardLoc.common.divText("file-png.png")).toBeVisible();
    });
  });
});

test.describe("Verify function for update business tests", async () => {
  let loginPage: LoginPage;
  let businessPage: BusinessPage;

  test.beforeEach("Login and verify data in modal update business", async ({ page, conf }, testInfo: TestInfo) => {
    let dataFromAPI: any;
    let businessExist: string = testInfo.tags.includes('@verifed') ? conf.data.business_name_verified : conf.data.business_name;

    //Login and redirect to Business Page
    loginPage = new LoginPage(page);
    businessPage = new BusinessPage(page);
    await loginPage.open();
    await loginPage.login(conf.data.username, conf.data.password);
    await businessPage.open();

    //Verify detail and modal data update
    await test.step("Search and verify business exist", async () => {
      await businessPage.businessLoc.inputSearch.fill(businessExist);
      await expect(businessPage.dashboardLoc.dataExistInTableRow(businessExist).first()).toBeVisible();
      await businessPage.waitForSecond(2)
      await businessPage.dashboardLoc.dataExistInTableRow(businessExist).first().click({ force: true });
    })

    await test.step("Verify detail page", async () => {
      await expect(businessPage.businessLoc.nameDetailExist(businessExist)).toBeVisible();
      dataFromAPI = await businessPage.fetchDetailBusiness();
      const dataFromUI = await businessPage.getBusinessDetailUI();
      expect(dataFromAPI).toEqual(dataFromUI);
    })

    await test.step("Verify modal update", async () => {
      await businessPage.dashboardLoc.buttonUpdate.click();
      await expect(businessPage.businessLoc.modalFormHeader).toBeVisible();

      const actual = (await businessPage.businessLoc.inputName.evaluate(el => {
        const text = (el.textContent || "").trim();
        // @ts-ignore
        const val = (el.value ?? "").trim();
        return val || text;
      })) as string;

      expect(actual).toContain(businessExist);
      const dataUpdateUI = await businessPage.getBusinessModalUpdateUI();
      expect(dataUpdateUI).toEqual(dataFromAPI);
    })
  })

  test('BUSINESS_UPDATE_004 - Verify that updating with already-verified business', {
    tag: ['@BUSINESS_UPDATE_004', '@business_update', '@function', '@verifed']
  }, async ({ }) => {
    await businessPage.businessLoc.inputName.click();
    await expect(businessPage.businessLoc.modalSuggestion).toBeVisible();
  });

  test('BUSINESS_UPDATE_005 - Verify when updating an unverified business to one that already exists', {
    tag: ['@BUSINESS_UPDATE_005', '@business_update', '@function']
  }, async ({ conf }) => {
    await businessPage.businessLoc.inputName.fill(conf.data.business_name_updated);
    await businessPage.waitForSecond(2);
    await businessPage.dashboardLoc.buttonUpdateInForm.click();

    await expect(businessPage.businessLoc.msgErrorDuplicateBusiness).toBeVisible();
    await expect(businessPage.businessLoc.modalFormHeader).toBeVisible();
  });

  test("BUSINESS_012 - Verify that the business's address update process successfully normalizes the address", {
    tag: ['@BUSINESS_012', '@business_update', '@function']
  }, async ({ conf }) => {
    await test.step("Clear old address", async () => {
      await businessPage.waitForSecond(1);
      await businessPage.dashboardLoc.modal.inputByID("input_address_1").clear();
      await businessPage.dashboardLoc.modal.inputByID("input_city").clear();
      await businessPage.dashboardLoc.buttonUpdateInForm.click();

      await expect(businessPage.dashboardLoc.modal.headerModal("Business Detail")).not.toBeVisible();
      await expect(businessPage.businessLoc.addressDetail).toContainText("--");
    })

    await test.step("Verify update address and city to normalizes text", async () => {
      await businessPage.dashboardLoc.buttonByText("Update").first().click();
      await expect(businessPage.dashboardLoc.modal.headerModal("Business Detail")).toBeVisible();
      await businessPage.waitForSecond(1);

      await businessPage.dashboardLoc.modal.inputByID("input_address_1").fill(conf.data.address);
      await businessPage.dashboardLoc.modal.inputByID("input_city").fill(conf.data.city);
      await businessPage.dashboardLoc.buttonUpdateInForm.click();

      await expect(businessPage.dashboardLoc.modal.headerModal("Business Detail")).not.toBeVisible();
      await expect(businessPage.businessLoc.addressDetail).toContainText(conf.expect.address);
      await expect(businessPage.businessLoc.addressDetail).toContainText(conf.expect.city);
    })
  });

  test("BUSINESS_016 - Verify update business", {
    tag: ['@BUSINESS_016', '@business_update', '@function']
  }, async ({ conf }) => {
    const createFormData = conf.data.input_update;
    await test.step("Clear all data in this business", async () => {
      for (const fieldConfig of createFormData) {
        await businessPage.dashboardLoc.modal.inputByID(fieldConfig.input_field).clear();
        await expect(businessPage.dashboardLoc.modal.inputByID(fieldConfig.input_field)).toHaveValue("");
      }
      await businessPage.dashboardLoc.modal.headerModal("Business Detail").click();
      await businessPage.dashboardLoc.buttonByText("Update").nth(1).click();

      await expect(businessPage.businessLoc.msgSuccess.first()).toBeVisible();
      await businessPage.dashboardLoc.btnClosePopupNotification.click();
      await expect(businessPage.dashboardLoc.modal.headerModal("Business Detail")).not.toBeVisible();
    });

    await test.step("Verify reopen close modal without change data", async () => {
      await businessPage.waitForSecond(2);
      await businessPage.dashboardLoc.buttonByText("Update").first().click();
      await expect(businessPage.dashboardLoc.modal.headerModal("Business Detail")).toBeVisible();
      await businessPage.businessLoc.btnCloseModalUpdate.click();
      await expect(businessPage.dashboardLoc.modal.headerModal("Business Detail")).not.toBeVisible();
    });

    await test.step("Fill data to update business", async () => {
      await businessPage.dashboardLoc.buttonByText("Update").first().click();
      await expect(businessPage.dashboardLoc.modal.headerModal("Business Detail")).toBeVisible();
      await businessPage.waitForSecond(2);

      for (const fieldConfig of createFormData) {
        const fieldInput = businessPage.dashboardLoc.modal.inputByID(fieldConfig.input_field).first();
        switch (fieldConfig.type) {
          case "input":
            await fieldInput.fill(fieldConfig.value);
            await expect(fieldInput).toHaveValue(fieldConfig.value);
            break;
          case "select":
            await fieldInput.fill(fieldConfig.value);
            await expect(businessPage.businessLoc.create.optionDropdown(fieldConfig.value)).toBeVisible();
            await businessPage.businessLoc.create.optionDropdown(fieldConfig.value).click();
            break;
          default:
            console.log(`Unknown field type: ${fieldConfig.type} for ${fieldConfig.input_field}`);
        }
      }

      await businessPage.dashboardLoc.modal.headerModal("Business Detail").click();

      // Verify cancel update business
      await businessPage.businessLoc.btnCloseModalUpdate.click();
      await expect(businessPage.dashboardLoc.buttonByText("Back").last()).toBeVisible();
      await businessPage.dashboardLoc.buttonByText("Back").last().click();

      // Verify update data
      await businessPage.dashboardLoc.buttonByText("Update").nth(1).click();

      await expect(businessPage.businessLoc.msgSuccess).toBeVisible();
      await businessPage.dashboardLoc.btnClosePopupNotification.click();
      await expect(businessPage.dashboardLoc.modal.headerModal("Business Detail")).not.toBeVisible();
    });
  });
})