import { MarketingPermission, ContactsSelectionType } from "@komi-app/fans-sdk";
import { CountQueryParameters, PaginationQueryParameters, usePagination } from "hooks/usePagination";
import { services } from "services";
import { IFansService } from "services/FansService";

export interface FanSchema {
  talentProfileId: string;
  fanId: string;
  moduleId: string;
  createdAt: number | string;
  updatedAt: number | string;
  phone_number: string;
  email: string;
  date_of_birth: string;
  country_code: string;
  full_name: string;
  id: string; // this does exist, adding it until we move to fans-sdk types
}

//Snake case received from database.
export interface FanResponseSchema {
  talent_profile_id: string;
  fan_id: string;
  module_id: string;
  created_at: number | string;
  updated_at: number | string;
  phone_number: string;
  email: string;
  date_of_birth: string;
  country_code: string;
  full_name: string;
  id: string;
}

export type FanWithCursorResponseSchema = FanResponseSchema & {
  cursor: string | null;
};

export type FanTableSchema = Omit<FanSchema, "email"> & {
  email: string[];
};

export type FanTableWithCursorSchema = FanTableSchema & {
  cursor: string | null;
};

// This function fetches a list of fans and cleans the data before returning the cleaned list.
export const getFansList = async (
  currentPage: number,
  pageSize: number,
  filter: MarketingPermission,
  searchTerm: string
) => {
  try {
    // Fetch fans list with a limit of {pageSize} fans per request.
    const response = await services.fans().getFans(
      currentPage,
      pageSize,
      filter,
      searchTerm
    );

    // Return an empty array if there's no response.
    if (!response) return [];
    const cleanedFans: FanTableSchema[] = [];

    response.forEach((submissionRow) => {
      // Find if the fan already exists in the cleanedFans array.

      // If fan does not exist, create a new fan object and add to the array.
      const fan = {
        talentProfileId: submissionRow.talent_profile_id,
        fanId: submissionRow.fan_id,
        moduleId: submissionRow.module_id,
        createdAt: submissionRow.created_at,
        updatedAt: submissionRow.updated_at,
        phone_number: submissionRow.phone_number,
        date_of_birth: submissionRow.date_of_birth,
        country_code: submissionRow.country_code,
        full_name: submissionRow.full_name,
        email: [submissionRow.email],
        id: submissionRow.id,
      };
      cleanedFans.push(fan);
    });
    return cleanedFans;
  } catch (error) {
    console.error("Error fetching fans list:", error);
    return [];
  }
};

export const getFansListWithCursor = async (
  queryParams: PaginationQueryParameters,
  filter: MarketingPermission,
  searchTerm: string
) => {
  try {
    // Fetch fans list with a limit of {pageSize} fans per request.
    const response = await services.fans().getFansWithCursor(
      queryParams,
      filter,
      searchTerm
    );

    // Return an empty array if there's no response.
    if (!response) return [];
    const cleanedFans: FanTableWithCursorSchema[] = [];

    response.forEach((submissionRow) => {
      // Find if the fan already exists in the cleanedFans array.

      // If fan does not exist, create a new fan object and add to the array.
      const fan = {
        talentProfileId: submissionRow.talent_profile_id,
        fanId: submissionRow.fan_id,
        moduleId: submissionRow.module_id,
        createdAt: submissionRow.created_at,
        updatedAt: submissionRow.updated_at,
        phone_number: submissionRow.phone_number,
        date_of_birth: submissionRow.date_of_birth,
        country_code: submissionRow.country_code,
        full_name: submissionRow.full_name,
        email: [submissionRow.email],
        id: submissionRow.id,
        cursor: submissionRow.cursor,
      };
      cleanedFans.push(fan);
    });
    return cleanedFans;
  } catch (error) {
    console.error("Error fetching fans list:", error);
    return [];
  }
};

export const fetchTotalNumberOfPages = async (
  filter: MarketingPermission,
  searchTerm: string,
  setTotalNumberOfRecordWithPagination: (number: number) => void
): Promise<number> => {
  const totalNumberOfFans = await services.fans().getTotalFanCount(
    filter,
    searchTerm
  );
  setTotalNumberOfRecordWithPagination(totalNumberOfFans);
  const totalNumberOfPages = Math.ceil(totalNumberOfFans / 10);
  return totalNumberOfPages;
};

export const getTotalFanCount = async (
  countParams: CountQueryParameters,
  filter: MarketingPermission,
  searchTerm: string
): Promise<number> => {
  return await services.fans().getTotalFanCountWithCursor(
    countParams,
    filter,
    searchTerm
  );
};

export const deleteFans = async (
  fans: FanTableSchema[],
  isAllRowsSelected: boolean
): Promise<boolean> => {
  const deletionType = isAllRowsSelected ? ContactsSelectionType.ALLROWS : "";
  await services.fans().deleteFans(fans, deletionType);
  return true;
};

/**
 * A function that converts an epoch timestamp to
 * US date time
 * Note: Type string is handled as sometimes
 * type is received in string format.
 * @param dateTime The timestamp
 * @param type conversion type
 * @returns String
 */
export const epochToDateTimeString = (
  dateTime: number | string,
  type: "dateTime" | "date"
): string => {
  if (dateTime === "") {
    return dateTime;
  }

  const date = new Date(Number(dateTime));
  const options: Intl.DateTimeFormatOptions = {
    month: "short",
    day: "2-digit",
    year: "numeric",
  };

  if (type === "dateTime") {
    options.hour = "numeric";
    options.minute = "2-digit";
    options.hour12 = true;
  }

  return date.toLocaleString("en-US", options);
};

export const downloadCSVFromJson = (
  filename: string,
  arrayOfJson: Record<string, any>[]
) => {
  // Convert JSON to CSV
  const replacer = (key: string, value: any) => (value === null ? "" : value);
  const header = Object.keys(arrayOfJson[0]);
  const csvRows = arrayOfJson.map((row) =>
    header
      .map((fieldName) => JSON.stringify(row[fieldName], replacer))
      .join(",")
  );
  const csv = [header.join(","), ...csvRows].join("\r\n");

  // Create link and download
  const link = document.createElement("a");
  const csvData = new Blob([csv], { type: "text/csv;charset=utf-8,%EF%BB%BF" });
  const csvUrl = URL.createObjectURL(csvData);

  link.setAttribute("href", csvUrl);
  link.setAttribute("download", filename);
  link.style.visibility = "hidden";

  document.body.appendChild(link);
  link.click();
  document.body.removeChild(link);
  URL.revokeObjectURL(csvUrl);
};

export const exportFans = async (
  fanList: FanTableSchema[],
  isAllRowsSelected: boolean
): Promise<ReturnType<IFansService["exportFansAndGetURL"]>> => {
  const exportType: string = isAllRowsSelected
    ? ContactsSelectionType.ALLROWS
    : "";

  return await services.fans().exportFansAndGetURL(fanList, exportType);
};

export async function updateTotalNumberOfPages(
  searchFilter: MarketingPermission,
  searchTerm: string,
  setter: (number: number) => void,
  setTotalNumberOfRecordWithPagination: (number: number) => void
) {
  const totalPages: number = await fetchTotalNumberOfPages(
    searchFilter,
    searchTerm,
    setTotalNumberOfRecordWithPagination
  );
  setter(totalPages);
}

export function triggerFileDownload(url: string): void {
  const link = document.createElement("a");
  link.href = url;
  link.style.display = "none";
  document.body.appendChild(link);

  link.click();

  document.body.removeChild(link);
}

export function useFansList(
  searchTerm: string,
  searchFilter: MarketingPermission
) {
  return usePagination(
    "fans",
    async (queryParams) => {
      return await getFansListWithCursor(queryParams, searchFilter, searchTerm);
    },
    async (countParams) => {
      return await getTotalFanCount(countParams, searchFilter, searchTerm);
    },
    10,
    "DESC",
    [searchFilter, searchTerm]
  );
}
