import { findBy, isPresent, keysToSnakeCase } from "@bigbinary/neeto-cist";
import {
  COMMON_SELECTORS,
  MEMBER_SELECTORS,
  MemberApis,
  TeamMembers,
} from "@neetoplaywright";
import { expect, Page } from "@playwright/test";
import { TFunction } from "i18next";
import { getI18nInstance } from "playwright-i18next-fixture";

import {
  AssertTeamMemberInfoProps,
  SelectTwoMembersAndVerifyChangeRoleButtonProps,
  SelectTwoMembersAndVerifyRemoveButtonProps,
} from "@poms/types";
import { BOOKING_SELECTORS, TRANSACTIONS_SELECTORS } from "@selectors";
import { TEAM_MEMBERS_SELECTORS } from "@selectors/teamMembers";
import { ExportFileType } from "@types";

import CommonUtils from "./commons/commands";

export class TeamMembersPage extends TeamMembers {
  t: TFunction;
  teamMembers: TeamMembers;
  memberApis: MemberApis;

  constructor(
    public page: Page,
    public commonUtils: CommonUtils
  ) {
    super({ page, neetoPlaywrightUtilities: commonUtils });

    this.t = getI18nInstance().t;
    this.memberApis = new MemberApis(commonUtils);
  }

  selectTwoMembersAndVerifyRemoveButton = async ({
    membersEmail,
    removeSelector,
  }: SelectTwoMembersAndVerifyRemoveButtonProps) => {
    await this.selectMultipleCheckbox(membersEmail);
    await this.page.getByTestId(BOOKING_SELECTORS.takeActionButton).click();
    await this.page.getByTestId(removeSelector).click();
    await expect(
      this.page.getByTestId(COMMON_SELECTORS.alertBox)
    ).toBeVisible();

    await Promise.all([
      this.page.getByTestId(COMMON_SELECTORS.alertModalSubmitButton).click(),
      this.commonUtils.verifyToast(),
    ]);
  };

  selectTwoMembersAndVerifyChangeRoleButton = async ({
    membersEmail,
    roleText,
    changedRoleText,
  }: SelectTwoMembersAndVerifyChangeRoleButtonProps) => {
    await Promise.all(
      membersEmail.map(email =>
        expect(
          this.page
            .getByRole("row", { name: email })
            .getByRole("cell", { name: roleText })
        ).toBeVisible()
      )
    );

    await this.selectMultipleCheckbox(membersEmail);
    await this.page.getByTestId(BOOKING_SELECTORS.takeActionButton).click();
    await this.page
      .getByRole("button")
      .getByText(this.t("neetoTeamMembers.buttons.changeRole"))
      .click();
    await this.page.getByRole("button").getByText(changedRoleText).click();

    await expect(this.page.getByTestId(COMMON_SELECTORS.alertTitle)).toHaveText(
      this.t("neetoTeamMembers.common.changeRole")
    );

    await Promise.all([
      this.page.getByTestId(COMMON_SELECTORS.alertModalSubmitButton).click(),
      this.commonUtils.verifyToast(),
    ]);

    await Promise.all(
      membersEmail.map(email =>
        expect(
          this.page
            .getByRole("row", { name: email })
            .getByRole("cell", { name: changedRoleText })
        ).toBeVisible()
      )
    );
  };

  selectMultipleCheckbox = async (membersEmail: string[]) => {
    for (const email of membersEmail) {
      await this.page
        .getByRole("row", { name: email })
        .getByRole("checkbox")
        .check();
    }
  };

  getMemberIdViaRequest = async (hostEmail: string) => {
    const teamMembersAPIResponse = await this.memberApis.fetch();
    const teamMembers = await teamMembersAPIResponse.json();

    const { id } = findBy<unknown, { id: string }>(
      { email: hostEmail.toLowerCase() },
      teamMembers.members
    );

    return id;
  };

  exportMemberDetails = async (
    adminEmail: string,
    fileType: ExportFileType = "excel"
  ) => {
    await this.page.getByTestId(TRANSACTIONS_SELECTORS.downloadButton).click();
    await expect(
      this.page.getByTestId(TEAM_MEMBERS_SELECTORS.exportMemberHeading)
    ).toHaveText(this.t("neetoTeamMembers.exportPane.title"));

    await this.page
      .getByTestId(TEAM_MEMBERS_SELECTORS.downloadAsRadioItem(fileType))
      .check();

    await this.page
      .getByTestId(TEAM_MEMBERS_SELECTORS.exportSubmitButton)
      .click();

    await this.commonUtils.verifyToast({
      message: this.t("toastr.success.exportMembers", { email: adminEmail }),
    });
  };

  navigateToTeamMembersShowPage = async (email: string) => {
    await this.searchAndVerifyMemberByEmail({ email });

    await this.page.getByTestId(MEMBER_SELECTORS.memberNameCell(email)).click();

    await expect
      .soft(this.page.getByTestId(COMMON_SELECTORS.heading))
      .toContainText(email, { timeout: 10_000 });
  };

  assertTeamMemberInfo = async ({
    email,
    role,
    country,
    timeZone,
    timeFormat,
    dateFormat,
    plan,
    noAvailabilitiesText,
    noSchedulingLinksText,
  }: Partial<AssertTeamMemberInfoProps>) => {
    const fields = [
      ["email", email],
      ["role", role],
      ["country", country],
      ["timeZone", timeZone],
      ["timeFormat", timeFormat],
      ["dateFormat", dateFormat],
      ["plan", plan],
    ] as const;

    await Promise.all(
      fields
        .filter(([, value]) => isPresent(value))
        .map(([key, value]) =>
          expect(
            this.page.getByTestId(TEAM_MEMBERS_SELECTORS.showPageHeader[key])
          ).toContainText(value, { timeout: 10_000 })
        )
    );

    isPresent(noAvailabilitiesText) &&
      (await expect(
        this.page.getByTestId(TEAM_MEMBERS_SELECTORS.noAvailabilitiesContainer)
      ).toContainText(noAvailabilitiesText, { timeout: 5_000 }));

    isPresent(noSchedulingLinksText) &&
      (await expect(
        this.page.getByTestId(TEAM_MEMBERS_SELECTORS.noSchedulingLinksContainer)
      ).toContainText(noSchedulingLinksText, { timeout: 5_000 }));
  };

  changeEmailViaRequest = async (
    oldEmail: string,
    newEmail: string,
    organizationRole = "Admin"
  ) => {
    const memberId = await this.getMemberIdViaRequest(oldEmail);

    await this.memberApis.update(
      memberId,
      keysToSnakeCase({
        email: newEmail,
        active: true,
        organizationRole,
      })
    );
  };
}
