import React from "react";

import { CATEGORY_FOR_AI_COMPUTING } from "../constants/app";
import { DecodedToken } from "../types/user";

export const timeUntilDate = (targetDateString: string | null): string => {
  if (!targetDateString) {
    return "N/A";
  }
  const targetDate = new Date(targetDateString);
  const currentDate = new Date();

  let years = targetDate.getFullYear() - currentDate.getFullYear();
  let months = targetDate.getMonth() - currentDate.getMonth();
  let days = targetDate.getDate() - currentDate.getDate();

  if (days < 0) {
    months--;
    days += new Date(
      currentDate.getFullYear(),
      currentDate.getMonth() + 1,
      0,
    ).getDate();
  }

  if (months < 0) {
    years--;
    months += 12;
  }

  let timeRemaining: string;

  if (years > 0) {
    timeRemaining = `${years} year${years > 1 ? "s" : ""}`;
  } else if (months > 0) {
    timeRemaining = `${months} month${months > 1 ? "s" : ""}`;
  } else if (days < 30) {
    timeRemaining = `${days} day${days > 1 ? "s" : ""}`;
  } else {
    timeRemaining = "";
  }

  return timeRemaining
    ? `in ${timeRemaining} (${targetDate.toLocaleDateString()})`
    : "Date has passed";
};

export const handleDownload = async (
  invoiceUrl: string,
  orderId: string,
  prefix: string = "INV",
) => {
  try {
    const response = await fetch(invoiceUrl);

    const blob = await response.blob();

    const url = window.URL.createObjectURL(blob);

    const link = document.createElement("a");
    link.href = url;
    link.download = `${prefix}_${orderId}.pdf`;

    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);

    window.URL.revokeObjectURL(url);
  } catch (error) {
    console.error("Download failed:", error);
  }
};

export const displayExactWalletBalance = (balance: string) => {
  const data = balance.split(".");
  if (!data?.[1]) return data[0];

  return data[0] + "." + data[1].substring(0, 5);
};

export const customGroupBy = (
  objectArray: any[],
  key: any,
  arrayValue: boolean = true,
) => {
  return objectArray.reduce((result, item) => {
    const groupKey = typeof key === "function" ? key(item) : item[key];
    if (!result[groupKey]) {
      result[groupKey] = [];
    }
    if (arrayValue) {
      result[groupKey].push(item);
    } else {
      result[groupKey] = item;
    }

    return result;
  }, {});
};

export const replaceForbiddenKeyword = (input: string): string => {
  return input.replace(/minter/gi, "Computer Device");
};
export const replaceComputerDevice = (input: string): string => {
  return input.replace(/computer device/gi, "minter");
};

/**
 * Function to check if any items in the data have a category code of "minter"
 * @param {Array} orderItems - Array of order items to check
 * @return {Boolean} - Returns true if any item has category code "minter", otherwise false
 */
export const hasMinterCategory = (orderItems) => {
  const MINTER = "minter";
  const SMART_PAY = "smart-pay";

  // Check if orderItems is valid
  if (!Array.isArray(orderItems) || orderItems.length === 0) {
    console.log("No items to check or invalid data format");
    return false;
  }

  // Check each item for category code "minter"
  for (const item of orderItems) {
    // Case 1: Direct categoryCode property (first data structure)
    if (item.categoryCode === MINTER || item.categoryCode === SMART_PAY) {
      return true;
    }

    // Case 2: Nested product.category.code (second data structure)
    if (
      (item.product &&
        item.product.category &&
        item?.product?.category?.code === MINTER) ||
      item?.product?.category?.code === SMART_PAY
    ) {
      return true;
    }

    // Also check in kitData if it exists (for first data structure)
    if (Array.isArray(item.kitData) && item.kitData.length > 0) {
      for (const kitItem of item.kitData) {
        if (
          kitItem.categoryCode === MINTER ||
          kitItem.categoryCode === SMART_PAY
        ) {
          return true;
        }
      }
    }
  }

  // No minter category found
  return false;
};

export const hasAICategory = (orderItems) => {
  // Check if orderItems is valid
  if (!Array.isArray(orderItems) || orderItems.length === 0) {
    console.log("No items to check or invalid data format");
    return false;
  }

  // Check each item for category code "minter"
  for (const item of orderItems) {
    // Case 1: Direct categoryCode property (first data structure)
    if (item.categoryCode === CATEGORY_FOR_AI_COMPUTING) {
      return true;
    }

    // Case 2: Nested product.category.code (second data structure)
    if (
      item.product &&
      item.product.category &&
      item?.product?.category?.code === CATEGORY_FOR_AI_COMPUTING
    ) {
      return true;
    }

    // Also check in kitData if it exists (for first data structure)
    if (Array.isArray(item.kitData) && item.kitData.length > 0) {
      for (const kitItem of item.kitData) {
        if (kitItem.categoryCode === CATEGORY_FOR_AI_COMPUTING) {
          return true;
        }
      }
    }
  }

  // No minter category found
  return false;
};

export const truncateString = (
  str: string,
  startLength: number = 5,
  endLength: number = 3,
): string => {
  if (str.length <= startLength + endLength) {
    return str;
  }

  return (
    str.substring(0, startLength) +
    "..." +
    str.substring(str.length - endLength)
  );
};

export const decodeJwt = (token: string): DecodedToken | null => {
  try {
    const base64Url = token.split(".")[1];
    const base64 = base64Url.replace(/-/g, "+").replace(/_/g, "/");
    const jsonPayload = decodeURIComponent(
      atob(base64)
        .split("")
        .map((c) => "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2))
        .join(""),
    );
    return JSON.parse(jsonPayload);
  } catch (error) {
    console.error("Error decoding JWT:", error);
    return null;
  }
};

export function withTimeout<T>(promise: Promise<T>, ms: number): Promise<T> {
  return new Promise((resolve, reject) => {
    const timeout = setTimeout(() => {
      reject(new Error(`Request timed out after ${ms}ms`));
    }, ms);

    promise
      .then((res) => {
        clearTimeout(timeout);
        resolve(res);
      })
      .catch((err) => {
        clearTimeout(timeout);
        reject(err);
      });
  });
}

/**
 * Renders a title with red asterisk if the title contains " *"
 * @param {string} title - The title string that may contain an asterisk
 * @returns {React.ReactNode} - JSX element with the title and red asterisk if present
 */
export const renderTitleWithRedAsterisk = (title: string): React.ReactNode => {
  if (title.includes(" *")) {
    const parts = title.split(" *");
    return React.createElement(
      React.Fragment,
      null,
      parts[0],
      React.createElement("span", { className: "text-red-500" }, " *"),
    );
  }
  return title;
};
