import { APIRequestContext, Page } from "@playwright/test";

export class BasePage {
  page: Page;
  baseUrl: string;
  request: APIRequestContext | undefined;
  businessSingular: string = "";
  businessPlural: string = "";

  constructor(page: Page, request?: APIRequestContext) {
    this.page = page;
    if (request) {
      this.request = request;
    }

    this.baseUrl = process.env.BASE_URL || "https://qa.loprx.com/";
  }

  get baseLoc() {
    return {
      personalContainer: this.genLoc("//div[@class='row personal-request business-customer']"),
      dashboardContainer: this.genLoc("//div[@id='root' and @class='dashboard-index']"),
      updateSuccessNotification: this.genLoc(`//div[contains(@class, 'page-wrapper')]//div[contains(@class, 'alert') and contains(normalize-space(), 'Updated Successfully!')]`),
      closeNotification: this.genLoc(`//div[contains(@class, 'page-wrapper')]//div[contains(@class, 'alert') and contains(normalize-space(), 'Updated Successfully!')]//a[@class='btn-close']`),
    };
  }

  async go(url: string) {
    return this.page.goto(url);
  }

  genFrameLoc(frLoc: string) {
    return this.page.frameLocator(frLoc);
  }

  genLoc(loc: string) {
    return this.page.locator(loc);
  }

  loadBusinessNames(businessSingular: string, businessPlural: string) {
    this.businessSingular = businessSingular;
    this.businessPlural = businessPlural;
  }

  async waitAllRequestCompeleted() {
    await this.page.waitForLoadState("networkidle", { timeout: 30_000 });
  }

  async reload() {
    await this.page.reload();
  }

  async waitForSecond(time: number) {
    await this.page.waitForTimeout(time * 1000);
  }

  async renderTemplate(
    template: string,
    variables: Record<string, string | number>
  ): Promise<string> {
    return template.replace(/{{\s*(\w+)\s*}}/g, (_, key) => {
      const value = variables[key];
      if (value === undefined) {
        throw new Error(`Missing value for template key: ${key}`);
      }
      return value.toString();
    });
  }

  async getTotalEntries(param: string) {
    try {
      const url = `${this.baseUrl}api/v1/${param}`;
      const resp = await this.page.request.get(url);
      const respJson = await resp.json();
      return respJson.total;
    } catch (error) {
      console.log(error);
    }
  }

  async getTotalEntriesByTabs(page: string, group: string, isArchived: boolean = false, additionalParams?: string) {
    try {
      const baseQuery = `is_archived=${isArchived}&group=${group}`;
      const fullQuery = additionalParams ? `${baseQuery}&${additionalParams}` : baseQuery;
      const url = `${this.baseUrl}api/v1/${page}?${fullQuery}`;
      const resp = await this.page.request.get(url);
      const respJson = await resp.json();
      return respJson.total;
    } catch (error) {
      console.log(error);
    }
  }

  async normalizePhone(phone: string | null) {
    if (!phone) return null;
    return phone.replace(/\)\s+/, ")").replace(/\s*-\s*/, "-");
  };

  async getInfoDetail<T>(type: string): Promise<T> {
    const currentUrl = this.page.url();
    const id = currentUrl.substring(currentUrl.lastIndexOf("/") + 1);
    const API = `${this.baseUrl}api/v1/${type}/${id}?return_type=json`;

    const resp = await this.page.request.get(API);

    if (!resp.ok) {
      throw new Error(
        `HTTP error! Status: ${resp.status}, URL: ${API}, Body: ${await resp.text()}`
      );
    }

    const respJson = await resp.json();
    if (!respJson.data) {
      throw new Error(`No "data" field in response: ${JSON.stringify(respJson)}`);
    }

    return respJson.data as T;
  }

  async filterSingleField(type: string, field: string, data: string, fieldFilter: string): Promise<any[]> {
    const param = (field === "updated" || field === "created")
      ? encodeURIComponent(data)
      : data;

    const url = `${this.baseUrl}api/v1/${type}?return_type=json&page=1&s=&is_archived=false&${field}=${param}`;
    const resp = await this.page.request.get(url);
    const respJson = await resp.json();
    return respJson.data.map((item: { [x: string]: any; }) => item[fieldFilter])
  }

  async getTotalMemberInBusiness(): Promise<number> {
    const url = `${this.baseUrl}api/v1/members?return_type=json`;
    const resp = await this.page.request.get(url);
    const respJson = await resp.json();
    return respJson.total;
  }
}
