import { expect, Page } from "@playwright/test";
import { TIMEOUT } from "../constant/timeout";
interface PWData {
  testId: string;
  value: string;
  extraLocator?: string;
}
export class PW {
  private page: Page;
  constructor(page: Page) {
    this.page = page;
  }
  isVisible(testId: string, timeout = 120000) {
    return expect(this.getElement(testId)).toBeVisible({ timeout });
  }
  async isEmpty(testId: string, timeout = TIMEOUT.VALIDATE_WAITING) {
    if (testId.startsWith("tree-sel-")) {
      await this.isTreeDropDownListEmpty(testId);
    } else if (testId.startsWith("sel-tags-")) {
      await expect(
        this.page.getByTestId(testId).locator(".ant-select-selection-item"),
      ).toHaveCount(0, { timeout });
    } else if (testId.startsWith("sel-")) {
      await this.isDropDownListEmpty(testId);
    } else if (testId.startsWith("txt-") || testId.startsWith("txa-")) {
      await this.isTextInputEmpty(testId);
    } else if (testId.startsWith("pp-multi-")) {
      await expect(
        this.page.getByTestId(testId).locator(".ant-tag"),
      ).toHaveCount(0, { timeout });
    } else {
      throw new Error(`Chưa có hàm kiểm tra isEmpty cho testId ${testId}`);
    }
  }
  async valueShouldBe(
    testId: string,
    expectedValue: string,
    timeout = TIMEOUT.VALIDATE_WAITING,
  ) {
    if (testId.startsWith("sel-") || testId.startsWith("tree-sel-")) {
      await expect(
        this.getElement(testId).locator(".ant-select-selection-item"),
      ).toHaveText(expectedValue, { timeout });
    }
    if (testId.startsWith("txt-") || testId.startsWith("txa-")) {
      await expect(this.getElement(testId)).toHaveValue(expectedValue, {
        timeout,
      });
    }
  }
  async valueShouldContain(
    testId: string,
    expectedValue: string,
    timeout = TIMEOUT.VALIDATE_WAITING,
  ) {
    if (testId.startsWith("sel-") || testId.startsWith("tree-sel-")) {
      await expect(
        this.getElement(testId).locator(".ant-select-selection-item"),
      ).toContainText(expectedValue, { timeout });
    }
    if (testId.startsWith("txt-") || testId.startsWith("txa-")) {
      await expect(this.getElement(testId)).toContainText(expectedValue, {
        timeout,
      });
    }
  }
  async isTextInputEmpty(testId: string) {
    await this.isVisible(testId);
    await expect(this.getElement(testId)).toHaveValue("");
  }
  async isTreeDropDownListEmpty(testId: string) {
    await this.isVisible(testId);
    await expect(
      this.getElement(testId).locator(".ant-select-selection-placeholder"),
    ).toBeVisible();
  }
  async isDropDownListEmpty(testId: string) {
    await this.isVisible(testId);
    await expect(
      this.getElement(testId).locator(".ant-select-selection-placeholder"),
    ).toBeVisible();
  }
  getElement(testId: string) {
    return this.page.getByTestId(testId);
  }
  async arrowDown() {
    this.page.keyboard.press("ArrowDown");
  }
  async enter() {
    return this.page.keyboard.press("Enter");
  }
  wait(timeout = 500) {
    return this.page.waitForTimeout(timeout);
  }
  async clickButton(testId: string) {
    return await this.getElement(testId).click();
  }
  async inputText(testId: string, text: string) {
    await this.getElement(testId).fill(text);
    await expect(this.getElement(testId)).toHaveValue(text);
  }
  async checkListValueDropdownListTags(
    testId: string,
    expectedValues: string[],
  ) {
    await this.getElement(testId).click();
    await expect(
      this.getElement(testId).locator(
        ".ant-select-selection-item-content:visible",
      ),
      {
        message: "Lỗi: Số lượng tags không giống số lượng mong muốn",
      },
    ).toHaveCount(expectedValues.length);
    for (const giaTri of expectedValues) {
      // Lọc ra cái option chứa giá trị đó và ép nó phải đang hiển thị trên màn hình
      await expect(
        this.getElement(testId)
          .locator(".ant-select-selection-item-content:visible")
          .filter({ hasText: giaTri })
          .first(),
        {
          message: "Lỗi: Giá trị mong đợi không đúng",
        },
      ).toBeVisible();
    }
  }
  async checkListValueDropdownList(testId: string, expectedValues: string[]) {
    await this.getElement(testId).click();
    await expect(
      this.page.locator(".ant-select-item-option-content:visible"),
    ).toHaveCount(expectedValues.length);
    for (const giaTri of expectedValues) {
      // Lọc ra cái option chứa giá trị đó và ép nó phải đang hiển thị trên màn hình
      await expect(
        this.page
          .locator(".ant-select-item-option-content")
          .filter({ hasText: giaTri })
          .first(),
      ).toBeVisible();
    }
  }

  async checkSearchDropdownHasOption(testId: string, keyword: string) {
    await this.isVisible(testId);

    await this.getElement(testId).getByRole("combobox").fill(keyword);

    const danhSachOptions = this.page.locator(
      ".ant-select-item-option-content",
    );

    // Lọc ra các option chứa keyword, lấy cái đầu tiên tìm thấy và ép nó phải tồn tại
    await expect(
      danhSachOptions.filter({ hasText: keyword }).first(),
    ).toBeVisible();
  }

  async checkSearchTreeDropdownHasOption(testId: string, keyword: string) {
    await this.isVisible(testId);

    await this.getElement(testId).getByRole("combobox").fill(keyword);

    const danhSachOptions = this.page.locator(".ant-select-tree-title");

    // Lọc ra các option chứa keyword, lấy cái đầu tiên tìm thấy và ép nó phải tồn tại
    await expect(
      danhSachOptions.filter({ hasText: keyword }).first(),
    ).toBeVisible();
  }

  async inputDropDownList(testId: string, optionText?: string) {
    if (!optionText || optionText.trim() === "") {
      await this.getElement(testId).click();
      await this.wait(TIMEOUT.CONTROL_LOADING);
      await this.enter();
      await expect(
        this.getElement(testId).locator(".ant-select-selection-item"),
        {
          message: `Dropdown [${testId}] vẫn rỗng sau khi chọn giá trị đầu tiên`,
        },
      ).toBeVisible({ timeout: TIMEOUT.VALIDATE_WAITING });
    } else {
      await this.getElement(testId).click();
      await this.page
        .locator(`.ant-select-item-option-content:text-is("${optionText}")`)
        .click();
      await expect(
        this.getElement(testId).locator(".ant-select-selection-item"),
        {
          message: `Dropdown [${testId}] không hiển thị giá trị "${optionText}" sau khi chọn`,
        },
      ).toHaveText(optionText, { timeout: TIMEOUT.VALIDATE_WAITING });
    }
  }
  async inputTreeDropDown(
    testId: string,
    optionText?: string,
    extraLocator?: string,
  ) {
    if (!optionText || optionText.trim() === "") {
      await this.getElement(testId).click();
      await this.wait(TIMEOUT.CONTROL_LOADING);
      await this.arrowDown();
      await this.enter();
      await expect(
        this.getElement(testId).locator(".ant-select-selection-item"),
        {
          message: `Tree dropdown [${testId}] vẫn rỗng sau khi chọn giá trị đầu tiên`,
        },
      ).toBeVisible({ timeout: TIMEOUT.VALIDATE_WAITING });
    } else {
      await this.getElement(testId).click();
      const locator = extraLocator
        ? this.page.locator(
            `.ant-select-tree-title ${extraLocator}:text-is("${optionText}")`,
          )
        : this.page.locator(`.ant-select-tree-title:text-is("${optionText}")`);
      await locator.click();
      await expect(
        this.getElement(testId).locator(".ant-select-selection-item"),
        {
          message: `Tree dropdown [${testId}] không hiển thị giá trị "${optionText}" sau khi chọn`,
        },
      ).toContainText(optionText, { timeout: TIMEOUT.VALIDATE_WAITING });
    }
  }
  async inputDropDownTagsList(testId: string, tags: string[]) {
    const element = this.getElement(testId);
    await element.click();
    // Nhập tag thứ 1
    for (const tag of tags) {
      await element.pressSequentially(tag);
      await this.enter();
    }
    this.checkListValueDropdownListTags(testId, tags);
  }
  async inputTextArea(testId: string, text: string) {
    await this.getElement(testId).fill(text);
    await expect(this.getElement(testId)).toHaveValue(text);
  }
  async inputDatetime(testId: string, datetime: string) {
    await this.clickButton(testId);
    await this.getElement(testId).fill(datetime);
    await this.enter();
    await expect(this.getElement(testId), {
      message: `Ô ngày tháng [${testId}] không hiển thị giá trị "${datetime}" sau khi nhập`,
    }).toHaveValue(datetime, { timeout: TIMEOUT.VALIDATE_WAITING });
  }

  /**
   *
   * @param order thứ tự của people picker trên form, tính từ 1 trở đi. Ví dụ: 1 = người tạo, 2 = người duyệt, v.v... (cái này để xác định được selector chính xác vì có thể có nhiều people picker trên form)
   * @param name text tìm kiếm user
   */
  async inputPeoplePicker(testId: string, value: string) {
    const emails = value.split(",").map((email) => email.trim());
    const peoplePicker = this.getElement(testId);
    for (const email of emails) {
      await peoplePicker.locator(".ant-select-selection-search-input").click();
      await peoplePicker
        .locator(".ant-select-selection-search-input")
        .pressSequentially(email, { delay: 200 });
      await this.wait(5000); // Chờ kết quả load ra
      await this.enter();
    }
    await expect(peoplePicker.locator(".ant-tag"), {
      message: `People picker [${testId}] không hiển thị đủ ${emails.length} người sau khi chọn`,
    }).toHaveCount(emails.length, { timeout: TIMEOUT.VALIDATE_WAITING });
  }

  async inputRelatedECM(testId: string, value: string) {
    //Bấm nút thêm
    await this.clickButton(testId);
    //bấm vào ecm đầu tiên
    await this.page.locator(".ant-modal-root .ant-table-row").first().hover();
    await this.page
      .locator(".ant-modal-root .ant-table-row .ant-checkbox-wrapper")
      .first()
      .click();
    await this.page.getByTestId("btn-add-related").click();
    await this.isVisible("related-item-table");
  }

  async clearValue(testId: string) {
    if (testId.startsWith("sel-") || testId.startsWith("tree-sel-")) {
      await this.getElement(testId).locator(".ant-select-clear").click();
    }
    if (testId.startsWith("txt-") || testId.startsWith("txa-")) {
      await this.getElement(testId).fill("");
    }
  }

  async getValue(testId: string) {
    if (testId.startsWith("sel-") || testId.startsWith("tree-sel-")) {
      return await this.getElement(testId)
        .locator(".ant-select-selection-item")
        .innerText();
    }
  }

  async batchInput(data: PWData[], checkBranch = false) {
    for (const item of data) {
      // if (!item.value) continue;
      if (item.testId.startsWith("sel-tags")) {
        await this.inputDropDownTagsList(item.testId, item.value.split(","));
        continue;
      }
      if (item.testId.startsWith("txt-")) {
        await this.inputText(item.testId, item.value);
        continue;
      }
      if (item.testId.startsWith("txa-")) {
        await this.inputTextArea(item.testId, item.value);
        continue;
      }
      if (item.testId.startsWith("date-")) {
        await this.inputDatetime(item.testId, item.value);
        continue;
      }
      if (item.testId.startsWith("sel-")) {
        await this.inputDropDownList(item.testId, item.value);
        continue;
      }
      if (item.testId.startsWith("tree-sel-")) {
        await this.inputTreeDropDown(
          item.testId,
          item.value,
          item.extraLocator,
        );
        continue;
      }
      if (item.testId.startsWith("pp-multi-")) {
        await this.inputPeoplePicker(item.testId, item.value);
        continue;
      }
      if (item.testId.startsWith("btn-add-related-ecm")) {
        await this.inputRelatedECM(item.testId, item.value);
        continue;
      }
    }
    if (checkBranch) {
      //kiểm tra Loại hồ sơ có phải là loại dự án hay không
      const dropdownDuAn = this.getElement("sel-duAn");
      let dangHienThi = false;

      try {
        // Chờ tối đa 2 giây xem nó có ngoi lên không
        await dropdownDuAn.waitFor({ state: "visible", timeout: 2000 });
        dangHienThi = true;
      } catch (e) {
        dangHienThi = false; // Quá 2 giây không thấy -> Chắc chắn nó bị ẩn
      }

      if (dangHienThi) {
        await this.inputDropDownList("sel-duAn");
      }
    }
  }
}
