import { test, expect } from "../../../fixtures/index";
import { ContactPage } from "../../../pom/contact/contact.page";
import { LoginPage } from "../../../pom/login.page";

test.describe("CRUD operations for contact tests", async () => {
    let loginPage: LoginPage;
    let contactPage: ContactPage;

    test.beforeEach(async ({ page, conf }) => {
        loginPage = new LoginPage(page);
        contactPage = new ContactPage(page);
        contactPage.loadBusinessNames(
            conf.data.business_singular,
            conf.data.business_plural
        );

        await test.step("Navigate to login page", async () => {
            await loginPage.open();
            await page.waitForLoadState('networkidle');
        });

        await test.step("Perform login authentication", async () => {
            await loginPage.login(conf.data.username, conf.data.password);
            await expect(loginPage.baseLoc.dashboardContainer).toBeVisible({ timeout: 15_000 });
        });

        if (conf.data.not_redirect) {
            return;
        }

        await test.step("Navigate to contact page", async () => {
            await contactPage.open();
            await page.waitForLoadState('networkidle');
        });
    });

    test("CONTACT_012 - Verify contact creation form validation", {
        tag: ["@CONTACT_012", "@contact", "@validate"],
    }, async ({ conf }) => {
        await test.step("Verify creation fails without required data", async () => {
            await contactPage.clickCreatePage();
            await contactPage.contactLoc.creating.createBtn.click();
            await expect(contactPage.dashboardLoc.modal.headerModal("New Contact")).toBeVisible();

            await expect(contactPage.contactLoc.creating.modalNotProvided).toBeVisible();
            await contactPage.contactLoc.creating.btnConfirmModalProvided.click();

            await expect(contactPage.dashboardLoc.creating.errorInput(conf.data.error_msg.empty_Fname).first()).toBeVisible();
            const countEmptyError = (await contactPage.dashboardLoc.creating.errorInput(conf.data.error_msg.empty_Fname).all()).length;
            expect(countEmptyError).toBe(2);
            await expect(contactPage.dashboardLoc.modal.headerModal("New Contact")).toBeVisible();
        });

        await test.step("Verify validation with invalid email", async () => {
            await contactPage.contactLoc.creating.email.fill(conf.data.invalid_data);
            await expect(contactPage.contactLoc.creating.email).toHaveValue(conf.data.invalid_data);

            await contactPage.contactLoc.creating.createBtn.click();
            await expect(contactPage.dashboardLoc.creating.errorInput(conf.data.error_msg.invalid_email)).toBeVisible();
            await expect(contactPage.dashboardLoc.modal.headerModal("New Contact")).toBeVisible();
        });

        await test.step("Verify validation with data exceeding limits", async () => {
            const invalidData = conf.data.invalid_data;

            await contactPage.contactLoc.creating.firstName.fill(invalidData);
            await expect(contactPage.contactLoc.creating.firstName).toHaveValue(invalidData);

            await contactPage.contactLoc.updating.inputLname.fill(invalidData);
            await expect(contactPage.contactLoc.updating.inputLname).toHaveValue(invalidData);

            await contactPage.contactLoc.updating.inputTag.fill(invalidData);
            await contactPage.contactLoc.updating.dropdownAddTag(invalidData).click();
            await expect(contactPage.contactLoc.updating.tagHadCreateUpdate(invalidData)).toBeVisible();
            await contactPage.dashboardLoc.modal.headerModal("New Contact").click();

            await contactPage.contactLoc.creating.createBtn.click();

            await expect(contactPage.dashboardLoc.creating.errorInput(conf.data.error_msg.exceed_Fname)).toBeVisible();
            await expect(contactPage.dashboardLoc.creating.errorInput(conf.data.error_msg.exceed_Lname)).toBeVisible();
            await expect(contactPage.dashboardLoc.creating.errorInput(conf.data.error_msg.exceed_tag)).toBeVisible();
            await expect(contactPage.dashboardLoc.modal.headerModal("New Contact")).toBeVisible();
        });
    });

    test("CONTACT_013 - Verify successful contact creation without creating another", {
        tag: ["@CONTACT_013", "@contact", "@function"],
    }, async ({ conf }) => {
        const emailContact = await contactPage.getRanmdomEmail(conf.data.email);
        const firstName = conf.data.first_name;

        await test.step("Open contact creation modal", async () => {
            await contactPage.clickCreatePage();
            await expect(contactPage.dashboardLoc.modal.headerModal("New Contact")).toBeVisible();
        });

        await test.step("Fill contact data and verify create another option is unchecked", async () => {
            await contactPage.contactLoc.creating.firstName.fill(firstName);
            await contactPage.contactLoc.creating.email.fill(emailContact);

            await expect(contactPage.contactLoc.creating.firstName).toHaveValue(firstName);
            await expect(contactPage.contactLoc.creating.email).toHaveValue(emailContact);
            await expect(contactPage.contactLoc.creating.createAnotherContact).not.toBeChecked();
        });

        await test.step("Create contact and verify success without keeping modal open", async () => {
            await contactPage.contactLoc.creating.createBtn.click();

            await expect(contactPage.contactLoc.creating.messageCreatetSuccess).toBeVisible();
            await expect(contactPage.dashboardLoc.modal.headerModal("New Contact")).not.toBeVisible();
            await expect(contactPage.contactLoc.creating.dataFirstNameAdd(firstName)).toBeVisible();
            await expect(contactPage.contactLoc.creating.dataEmailAdd(emailContact)).toBeVisible();
        });
    });

    test("CONTACT_014 - Verify successful contact creation with creating another option", {
        tag: ["@CONTACT_014", "@contact", "@function"],
    }, async ({ conf }) => {
        const emailContact = await contactPage.getRanmdomEmail(conf.data.email);
        const firstName = conf.data.first_name;

        await test.step("Open contact creation modal", async () => {
            await contactPage.clickCreatePage();
            await expect(contactPage.dashboardLoc.modal.headerModal("New Contact")).toBeVisible();
        });

        await test.step("Fill contact data and enable create another contact option", async () => {
            // Fill business
            await contactPage.dashboardLoc.modal.inputByID("autocomplete_business_provider_id").fill(conf.data.business_name);
            await expect(contactPage.dashboardLoc.search.filter.popup.optionInput(conf.data.business_name)).toBeVisible();
            await contactPage.dashboardLoc.search.filter.popup.optionInput(conf.data.business_name).click();
            await contactPage.dashboardLoc.modal.inputContainByID("checkbox-use_business_address").check();
            await contactPage.dashboardLoc.common.popUpConfirm.click();

            await contactPage.contactLoc.creating.firstName.fill(firstName);
            await contactPage.contactLoc.creating.email.fill(emailContact);
            await contactPage.contactLoc.creating.createAnotherContact.check();

            await expect(contactPage.dashboardLoc.root).toMatchAriaSnapshot(contactPage.contactSnapshot.createAnotherContact);
            await expect(contactPage.contactLoc.creating.firstName).toHaveValue(firstName);
            await expect(contactPage.contactLoc.creating.email).toHaveValue(emailContact);
            await expect(contactPage.contactLoc.creating.createAnotherContact).toBeChecked();
        });

        await test.step("Create contact and verify modal remains open for another creation", async () => {
            await contactPage.contactLoc.creating.createBtn.click();
            await expect(contactPage.contactLoc.creating.messageCreatetSuccess).toBeVisible();
            await expect(contactPage.dashboardLoc.modal.headerModal("New Contact")).toBeVisible();
            await expect(contactPage.contactLoc.creating.dataFirstNameAdd(firstName)).toBeVisible();
            await expect(contactPage.contactLoc.creating.dataEmailAdd(emailContact)).toBeVisible();
            await expect(contactPage.dashboardLoc.root).toMatchAriaSnapshot(contactPage.contactSnapshot.createAnotherContact);
        });
    });

    test("CONTACT_015 - Verify contact creation failure with invalid data", {
        tag: ["@CONTACT_015", "@contact", "@function"],
    }, async ({ conf }) => {
        const firstName = conf.data.first_name;
        const invalidEmail = conf.data.email;

        await test.step("Open contact creation modal", async () => {
            await contactPage.clickCreatePage();
            await expect(contactPage.dashboardLoc.modal.headerModal("New Contact")).toBeVisible();
        });

        await test.step("Fill form with invalid email data", async () => {
            await contactPage.contactLoc.creating.firstName.fill(firstName);
            await contactPage.contactLoc.creating.email.fill(invalidEmail);
            await expect(contactPage.contactLoc.creating.firstName).toHaveValue(firstName);
            await expect(contactPage.contactLoc.creating.email).toHaveValue(invalidEmail);
        });

        await test.step("Verify creation fails with invalid email error", async () => {
            await contactPage.contactLoc.creating.createBtn.click();
            await expect(contactPage.contactLoc.creating.messageCraeteInvalidEmail).toBeVisible();
            await expect(contactPage.dashboardLoc.modal.headerModal("New Contact")).toBeVisible();
            await expect(contactPage.contactLoc.creating.firstName).toHaveValue(firstName);
        });
    });

    test("CONTACT_016 - Verify contact creation failure with existing contact", {
        tag: ["@CONTACT_016", "@contact", "@function"],
    }, async ({ conf }) => {
        const firstName = conf.data.first_name;
        const existingEmail = conf.data.email;

        await test.step("Open contact creation modal", async () => {
            await contactPage.clickCreatePage();
            await expect(contactPage.dashboardLoc.modal.headerModal("New Contact")).toBeVisible();
        });

        await test.step("Fill form with existing contact email", async () => {
            await contactPage.contactLoc.creating.firstName.fill(firstName);
            await contactPage.contactLoc.creating.email.fill(existingEmail);

            await expect(contactPage.contactLoc.creating.firstName).toHaveValue(firstName);
            await expect(contactPage.contactLoc.creating.email).toHaveValue(existingEmail);
        });

        await test.step("Verify creation fails with duplicate email error", async () => {
            await contactPage.contactLoc.creating.createBtn.click();

            await expect(contactPage.dashboardLoc.modal.headerModal("New Contact")).toBeVisible();
            await expect(contactPage.contactLoc.creating.blockMsgDuplicateEmail).toBeVisible();
            await expect(contactPage.contactLoc.textMsgDuplicateEmail).toContainText(existingEmail);
            await expect(contactPage.contactLoc.creating.firstName).toHaveValue(firstName);
        });
    });

    test("CONTACT_018 - Verify successfully contact information update", {
        tag: ["@CONTACT_018", "@contact", "@function"],
    }, async ({ conf, updateContactPage }) => {
        await test.step("Fill contact update form with new data", async () => {
            await updateContactPage.contactLoc.updating.inputPhoneNumber.fill(conf.data.phone_number);
            await updateContactPage.contactLoc.updating.inputTag.type(conf.data.tag, { delay: 100 });
            await updateContactPage.waitForSecond(1); // wait for dropdown to appear
            await updateContactPage.contactLoc.optionSelectTag(conf.data.tag).click();
            await updateContactPage.contactLoc.updating.inputAddress.fill(conf.data.address);
            await updateContactPage.contactLoc.updating.inputCity.fill(conf.data.city);
        });

        await test.step("Save changes and verify successful update", async () => {
            await updateContactPage.dashboardLoc.modal.headerModal("Contact Detail").click();
            await updateContactPage.dashboardLoc.buttonUpdateInForm.click({ force: true });
            await expect(updateContactPage.contactLoc.updating.msgUpdateSuccess).toBeVisible();
            await expect(updateContactPage.contactLoc.modalForm).not.toBeVisible();
            await expect(updateContactPage.contactLoc.updating.phoneDetail).toContainText(
                conf.data.phone_number.replace(/(\(\d{3}\)\s*\d{3})-(\d{4})/, "$1 - $2")
            );
            await updateContactPage.waitForSecond(1);
            const tags = await updateContactPage.contactLoc.updating.tagHadCreateDetail.allTextContents();
            expect(tags).toContain(`#${conf.data.tag}`);

            await updateContactPage.dashboardLoc.buttonUpdate.click();
            await expect(updateContactPage.contactLoc.updating.inputAddress).toHaveValue(conf.expect.address);
            await expect(updateContactPage.contactLoc.updating.inputCity).toHaveValue(conf.expect.city);
        });
    });

    test("CONTACT_019 - Verify contact update failure with invalid data", {
        tag: ["@CONTACT_019", "@contact", "@function"],
    }, async ({ conf, updateContactPage }) => {
        await test.step("Fill form with invalid email", async () => {
            await updateContactPage.contactLoc.updating.inputEmail.fill(conf.data.email_invalid);
            await expect(updateContactPage.contactLoc.updating.inputEmail).toHaveValue(conf.data.email_invalid);
        });

        await test.step("Verify update fails with invalid email error", async () => {
            await updateContactPage.dashboardLoc.buttonUpdateInForm.click();

            await expect(updateContactPage.contactLoc.updating.msgErrorInvalidEmail).toBeVisible();
            await expect(updateContactPage.contactLoc.modalForm).toBeVisible();
        });
    });

    test("CONTACT_020 - Verify contact update failure with existing email", {
        tag: ["@CONTACT_020", "@contact", "@function"],
    }, async ({ conf, updateContactPage }) => {
        await test.step("Fill form with existing contact email", async () => {
            await updateContactPage.contactLoc.updating.inputEmail.fill(conf.data.exist_email);
            await expect(updateContactPage.contactLoc.updating.inputEmail).toHaveValue(conf.data.exist_email);
        });

        await test.step("Verify update fails with duplicate email error", async () => {
            await updateContactPage.dashboardLoc.buttonUpdateInForm.click();

            await expect(updateContactPage.contactLoc.modalForm).toBeVisible();
            await expect(updateContactPage.contactLoc.textMsgDuplicateEmail).toBeVisible();
        });
    });

    test("CONTACT_021 - Verify contact update validation for character limits", {
        tag: ["@CONTACT_021", "@contact", "@validate"]
    }, async ({ conf, updateContactPage }) => {
        await test.step("Fill form with data exceeding character limits", async () => {
            await updateContactPage.contactLoc.updating.inputFname.fill(conf.data.first_name_long);
            await updateContactPage.contactLoc.updating.inputLname.fill(conf.data.last_name_long);
            await updateContactPage.contactLoc.updating.inputNote.fill(conf.data.note_long);
            await updateContactPage.contactLoc.updating.inputTag.fill(conf.data.tag_long);
            await updateContactPage.contactLoc.updating.dropdownAddTag(conf.data.tag_long).click();

            await expect(updateContactPage.contactLoc.updating.inputFname).toHaveValue(conf.data.first_name_long);
            await expect(updateContactPage.contactLoc.updating.inputLname).toHaveValue(conf.data.last_name_long);
            await expect(updateContactPage.contactLoc.updating.inputNote).toHaveValue(conf.data.note_long);
            await expect(updateContactPage.contactLoc.updating.tagHadCreateUpdate(conf.data.tag_long)).toBeVisible();
        });

        await test.step("Verify update fails with character limit validation errors", async () => {
            await updateContactPage.dashboardLoc.buttonUpdateInForm.click();

            await expect(updateContactPage.contactLoc.modalForm).toBeVisible();
            await expect(updateContactPage.contactLoc.msgErrorTooLongInput("first name")).toBeVisible();
            await expect(updateContactPage.contactLoc.msgErrorTooLongInput("last name")).toBeVisible();
            await expect(updateContactPage.contactLoc.msgErrorTooLongInput("tags")).toBeVisible();
            await expect(updateContactPage.contactLoc.msgErrorTooLongInput("note")).toBeVisible();
        });
    });

    test("CONTACT_023 - Verify contact business field clear and update functionality", {
        tag: ["@CONTACT_023", "@contact", "@function"]
    }, async ({ conf }) => {
        const contactName = conf.data.contact;
        const businessName = conf.data.business_name;

        await test.step("Verify contact has business information", async () => {
            await contactPage.getDetailCase(contactName);
            await contactPage.dashboardLoc.buttonUpdate.click();
            await expect(contactPage.contactLoc.modalForm.first()).toBeVisible();
            await expect(contactPage.contactLoc.updating.inputByName("business_provider_id")).toHaveValue(businessName);
        });

        await test.step("Clear business field and save changes", async () => {
            await contactPage.contactLoc.updating.inputByName("business_provider_id").clear();
            await expect(contactPage.contactLoc.updating.inputByName("business_provider_id")).not.toHaveValue(businessName);
            await contactPage.dashboardLoc.buttonUpdateInForm.click();
        });

        await test.step("Verify business field is cleared and restore business information", async () => {
            await contactPage.dashboardLoc.buttonUpdate.click();
            await contactPage.waitForSecond(1.5); // wait for loading form
            await expect(contactPage.contactLoc.updating.inputByName("business_provider_id")).toHaveValue("");

            await contactPage.contactLoc.updating.inputByName("business_provider_id").fill(businessName);
            await expect(contactPage.contactLoc.updating.optionBusiness(businessName)).toBeVisible();
            await contactPage.contactLoc.updating.optionBusiness(businessName).click();
            await expect(contactPage.contactLoc.updating.inputByName("business_provider_id")).toHaveValue(businessName);
            await contactPage.dashboardLoc.buttonUpdateInForm.click();
        });
    });

    test("CONTACT_027 - Verify crud Contact Group", {
        tag: ["@CONTACT_027", "@contact", "@function"]
    }, async ({ conf }) => {
        await test.step("Verify contact group had been delete", async () => {
            await contactPage.dashboardLoc.buttonByText("Contact Group").click();
            await contactPage.dashboardLoc.common.spanText("Contact Groups").waitFor({ state: 'visible' });
            await contactPage.search("Test Tag");
            await contactPage.waitForSecond(3)
            const dataTestTag = (await contactPage.dashboardLoc.table.itemInRow("Test Tag").all()).length;
            if (dataTestTag > 0) {
                await contactPage.contactLoc.contactGroup.btnDeleteContactGroup.first().click();
                await contactPage.dashboardLoc.common.popUpConfirm.click();
                await contactPage.dashboardLoc.btnClosePopupNotification.click();
            }
        })

        await test.step("Verify create new contact group", async () => {
            await contactPage.createContactGroupComplete(conf.data.input_create);
            await contactPage.verifyContactGroupInNewTab(
                conf.data.input_create[2].value,
                conf.data.input_create[0].value
            );
        });

        await test.step("Verify update contact group", async () => {
            await contactPage.updateContactGroupComplete(conf.data.input_create);
            await contactPage.verifyContactGroupInNewTab(
                conf.data.input_create[2].value,
                conf.data.input_create[0].value_update
            );
        });

        await test.step("Verify delete contact group", async () => {
            await contactPage.contactLoc.contactGroup.btnDeleteContactGroup.first().click();
            await contactPage.dashboardLoc.common.popUpConfirm.click();
            await contactPage.search(conf.data.input_create[0].value_update);
            await contactPage.verifyContactGroupInNewTab(conf.data.input_create[2].value, null);
        });
    })
});