export default function useUtils() {
  const requiredRule = (v: string) => !!v || "Required";

  const emailRule = (v: string): true | string => {
    const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    return regex.test(v) || "Please enter a valid email address";
  };

  const validateDate = (value: string): boolean | string => {
    const dateRegex = /^(0[1-9]|1[0-2])\/(0[1-9]|[12][0-9]|3[01])\/\d{4}$/;

    if (!dateRegex.test(value)) return "Invalid date format (MM/DD/YYYY)";

    return true;
  };

  function requireListRule(value: string[]) {
    return value.length ? "" : "Required";
  }

  const minOneMonthAdvance = (value: string): boolean | string => {
    if (!/^(0[1-9]|1[0-2])\/(0[1-9]|[12][0-9]|3[01])\/\d{4}$/.test(value)) {
      return "Invalid date format (MM/DD/YYYY)";
    }

    const [month, day, year] = value.split("/").map(Number);
    const selectedDate = new Date(year, month - 1, day);

    const currentDate = new Date();
    const minDate = new Date();
    minDate.setMonth(currentDate.getMonth() + 1); // 1 month in advance

    return (
      selectedDate >= minDate || "Date must be at least 1 month in advance"
    );
  };

  const passwordRule = (v: string) =>
    v.length >= 8 || "Password must be at least 8 characters long";

  const confirmPasswordRule =
    (newPassword: Ref<string>, confirmPassword: Ref<string>) => () =>
      confirmPassword.value === newPassword.value || "Passwords must match";

  const validateEmail = (email: Ref<string>, emailErrors: Ref<string[]>) => {
    emailErrors.value = [];

    if (!email.value) {
      emailErrors.value.push("Please input your email");
    } else {
      const result = emailRule(email.value);
      if (result !== true) {
        emailErrors.value.push(result);
      }
    }
  };

  function validEmail(email: string) {
    const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    return regex.test(email) || "Invalid email address";
  }

  const validateWord = (value: string): boolean | string => {
    if (value.trim().length < 3) return "Must be at least 3 characters";
    return true;
  };

  const validatePassword = (
    password: Ref<string>,
    passwordErrors: Ref<string[]>
  ) => {
    passwordErrors.value = [];

    if (!password.value) {
      passwordErrors.value.push("Please input your password");
    } else if (!passwordRule(password.value)) {
      passwordErrors.value.push("Password must be at least 8 characters long");
    }
  };

  function back() {
    useRouter().back();
  }

  function debounce<T extends (...args: any[]) => void>(
    func: T,
    wait: number
  ): (...args: Parameters<T>) => void {
    let timeoutId: ReturnType<typeof setTimeout>;

    return function (...args: Parameters<T>) {
      clearTimeout(timeoutId);
      timeoutId = setTimeout(() => func(...args), wait);
    };
  }

  function insertBetween(arr: any, elementToInsert: any) {
    return arr.flatMap((item: any, index: number, array: any) =>
      index < array.length - 1 ? [item, elementToInsert] : [item]
    );
  }

  function getNameInitials(name: string) {
    if (typeof name !== "string" || name.trim() === "") {
      return ""; // Default fallback for invalid input
    }

    const words = name.trim().split(/\s+/); // Split by spaces

    if (words.length === 1) {
      return words[0].slice(0, 2).toUpperCase(); // Take first two letters of the single word
    }

    return words
      .map((word) => word[0]?.toUpperCase()) // Take the first letter of each word and capitalize
      .join("")
      .slice(0, 2); // Limit to 2 characters
  }

  function getDimensions(
    file: File
  ): Promise<{ width: number; height: number }> {
    const img = new Image();
    img.src = URL.createObjectURL(file);
    return new Promise((resolve, reject) => {
      img.onload = () => {
        const width = img.width;
        const height = img.height;
        resolve({ width, height });
      };

      img.onerror = () => {
        reject(new Error("Failed to read image dimensions"));
      };
    });
  }

  async function getCountries() {
    try {
      const countries = await useNuxtApp().$api<Array<Record<string, any>>>(
        "https://restcountries.com/v3.1/all?fields=name,idd",
        { method: "GET" }
      );

      const uniqueCountries = new Map();

      countries.forEach((country) => {
        let suffixes = country.idd?.suffixes?.[0] || "";
        let code = `${country.idd?.root || ""}${suffixes}`;
        let name = country.name?.common || "";

        if (name && code && !uniqueCountries.has(code)) {
          uniqueCountries.set(code, { index: `${name}-${code}`, name, code });
        }
      });

      return Array.from(uniqueCountries.values()).sort((a, b) =>
        a.name.localeCompare(b.name)
      );
    } catch (error) {
      console.error(error);
      throw new Error("Failed to fetch countries.");
    }
  }

  const formatter = new Intl.NumberFormat("en-US", {
    minimumFractionDigits: 2,
    maximumFractionDigits: 2,
  });

  function formatNumber(
    amount: number,
    options: {
      currency?: string;
      locale?: string;
      useSymbol?: boolean;
      decimalPlaces?: number;
    } = {}
  ): string {
    const {
      currency,
      locale = "en-US",
      useSymbol = false,
      decimalPlaces = 2,
    } = options;

    return new Intl.NumberFormat(locale, {
      style: useSymbol && currency ? "currency" : "decimal",
      currency: currency || "USD", // Default currency (ignored if `useSymbol` is false)
      minimumFractionDigits: decimalPlaces,
      maximumFractionDigits: decimalPlaces,
    }).format(amount);
  }

  // 🔹 Examples:
  // console.log(formatNumber(1234.56)); // "1,234.56" (comma separator, 2 decimals)
  // console.log(formatNumber(1234.56, { decimalPlaces: 0 })); // "1,234" (no decimals)
  // console.log(formatNumber(1234.56, { useSymbol: true, currency: "USD" })); // "$1,234.56"
  // console.log(formatNumber(1234.56, { useSymbol: true, currency: "SGD", decimalPlaces: 0 })); // "S$1,234"
  // console.log(formatNumber(1234.56, { useSymbol: false, decimalPlaces: 0 })); // "1,234"
  // console.log(formatNumber(1234.56, { useSymbol: true, currency: "EUR", locale: "de-DE" })); // "1.234,56 €"
  // console.log(formatNumber(1234.56, { useSymbol: true, currency: "EUR", locale: "de-DE", decimalPlaces: 0 })); // "1.234 €"

  function convertPermissionsToArray(permissions: TPermissions) {
    return Object.entries(permissions).flatMap(([resource, actions]) =>
      Object.keys(actions).map((action) => `${resource}:${action}`)
    );
  }

  function redirect(link: string, page?: string) {
    const href = page ? `${link}/${page}` : link;

    window.location.href = href;
  }

  function computeTieredCost(seats: number, tiers: TPromoTier[]) {
    let totalCost = 0;

    for (let i = 0; i < tiers.length; i++) {
      let { min, max, price } = tiers[i];

      if (max === 0) max = Infinity; // Handle unlimited tier

      if (seats >= min) {
        let seatsInTier = Math.min(seats, max) - min + 1;
        totalCost += seatsInTier * price;
      }

      if (seats <= max) break; // Stop when all seats are counted
    }

    return totalCost;
  }

  const getColorStatus = (status: string) => {
    switch (status.toLowerCase()) {
      case "in-progress":
      case "in progress":
        return "warning";
      case "to-do":
      case "to do":
        return "#052439";
      case "complete":
      case "active":
        return "success";

      case "suspended":
        return "error";

      default:
        return "grey";
    }
  };

  function getStatusColor(status: string) {
    return status === "In-Progress"
      ? "#FB8C00"
      : ["Completed", "Resolved"].includes(status)
      ? "#4CAF50"
      : status === "Deleted"
      ? "error"
      : status === "For Review"
      ? "primary"
      : "grey-lighten-3";
  }

  function getOrigin() {
    if (process.client) {
      return window.location.origin;
    }
    return "";
  }

  const search = useState("search", () => "");

  //returns Oct 16, 2025, 03:45 PM // N/A format
  function formatDate(dateString: string) {
    if (!dateString) return "N/A";

    const date = new Date(dateString);
    return date.toLocaleDateString("en-US", {
      year: "numeric",
      month: "short",
      day: "numeric",
      hour: "2-digit",
      minute: "2-digit",
    });
  }

  // returns 16/10/2025, 15:45 format
  function UTCToLocalTIme(UTCDateTime: string) {
    if (!UTCDateTime) return "";
    const local = new Date(UTCDateTime);

    const formatted = local.toLocaleString("en-GB", {
      day: "2-digit",
      month: "2-digit",
      year: "numeric",
      hour: "2-digit",
      minute: "2-digit",
      hour12: false, // 24-hour format
    });

    return formatted;
  }

  // dd/mm/yyyy in local time
  function formatDateDDMMYYYYLocal(dateString: string) {
    if (!dateString) return "-";

    const date = new Date(dateString);
    const day = String(date.getDate()).padStart(2, "0");
    const month = String(date.getMonth() + 1).padStart(2, "0");
    const year = date.getFullYear();

    return `${day}/${month}/${year}`;
  }

  function formatNature(value: string): string {
    if (!value) return "";
    return value
      .split("_")
      .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
      .join(" ");
  }

  function replaceMatch(str: string, match: string, replace: string) {
    return str.replace(new RegExp(match, "g"), replace);
  }

  function setRouteParams(...args: Array<Record<string, string>>) {
    const params: Record<string, string> = {};

    args.forEach((arg) => {
      Object.entries(arg).forEach(([key, value]) => {
        if (value !== undefined && value !== null && value !== "") {
          params[key] = value;
        }
      });
    });

    return params;
  }

  function toOrdinal(n: number): string {
    const s = ["th", "st", "nd", "rd"];
    const v = n % 100;
    return n + (s[(v - 20) % 10] || s[v] || s[0]);
  }

  function formatDateISO8601(date: Date): string {
    const pad = (n: number) => n.toString().padStart(2, "0");
    const year = date.getFullYear();
    const month = pad(date.getMonth() + 1);
    const day = pad(date.getDate());
    const hours = pad(date.getHours());
    const minutes = pad(date.getMinutes());
    return `${year}-${month}-${day}T${hours}:${minutes}`;
  }

  function isValidBaseURL(baseURL: string | null) {
    if (!baseURL) return true;

    // Check if the baseURL starts with http:// or https://
    if (!baseURL.startsWith("http://") && !baseURL.startsWith("https://")) {
      return 'Base URL should start with "https://" or "http://"';
    }

    try {
      const url = new URL(baseURL);

      // Reject if there's any path beyond root
      if (url.pathname !== "/" && url.pathname !== "") {
        return "Invalid Base URL";
      }

      // Also reject if there’s a query or hash
      if (url.search || url.hash) {
        return "Invalid Base URL";
      }

      return ["http:", "https:"].includes(url.protocol)
        ? true
        : "Invalid Base URL";
    } catch (e: any) {
      return "Invalid Base URL";
    }
  }

  function formatCamelCaseToWords(key: string) {
    if (!key) return "";
    return key
      .replace(/([A-Z])/g, " $1")
      .replace(/^./, (str) => str.toUpperCase());
  }

  function calculateRemainingTime(
    item: Date | string | number | null | undefined
  ) {
    if (!item) return -1;
    const _date = new Date(item);
    if (isNaN(_date.getTime())) return -1;
    const creationTime = _date.getTime();
    const currentTime = Date.now();
    const differenceInMillis = currentTime - creationTime;
    const differenceInSeconds = Math.floor(differenceInMillis / 1000);
    const desiredDurationInSeconds = 24 * 60 * 60;
    const remainingTimeInSeconds =
      desiredDurationInSeconds - differenceInSeconds;
    console.log(remainingTimeInSeconds);
    return remainingTimeInSeconds;
  }

  const formatTime = (seconds: number) => {
    if (seconds <= 0 || isNaN(seconds)) return "00h 00m";
    const hours = Math.floor(seconds / 3600);
    const minutes = Math.floor((seconds % 3600) / 60);
    return `${String(hours).padStart(2, "0")}h ${String(minutes).padStart(
      2,
      "0"
    )}m`;
  };

  function standardFormatDateTime(date: string | Date) {
    if (!date) return "";

    const today = new Date(date);
    const year = today.getFullYear();
    let month = today.getMonth() + 1;
    let day = today.getDate();

    let hour = today.getHours();
    let minute =
      today.getMinutes() <= 9 ? `0${today.getMinutes()}` : today.getMinutes();

    if (day < 10) day = `0${day}`;
    if (month < 10) month = `0${month}`;

    return `${day}/${month}/${year} ${hour}:${minute}`;
  }

  function standardFormatDate(date: string | Date) {
    const today = new Date(date);
    const year = today.getFullYear();
    let month = today.getMonth() + 1;
    let day = today.getDate();

    if (day < 10) day = `0${day}`;
    if (month < 10) month = `0${month}`;

    return `${day}/${month}/${year}`;
  }

  const materialColors = [
    "red",
    "deep-purple",
    "light-blue",
    "green",
    "yellow",
    "deep-orange",
    "pink",
    "indigo",
    "cyan",
    "light-green",
    "amber",
    "brown",
    "purple",
    "blue",
    "teal",
    "lime",
    "orange",
    "blue-grey",
  ];

  function getInitial(name: string): string {
    if (typeof name !== "string") {
      return "";
    }
    const rgx: RegExp = /\b\w/g;

    const initials: string[] = name?.match(rgx) || [];

    return initials.join("").toUpperCase();
  }

  const fileToBase64 = (file: any): Promise<string> => {
    return new Promise((resolve, reject) => {
      const reader = new FileReader();
      reader.readAsDataURL(file);
      reader.onload = () => resolve(reader.result as string);
      reader.onerror = reject;
    });
  };

  async function getImage(url: string) {
    try {
      const response = await fetch(url, { method: "GET" });
      return response.blob();
    } catch (error: any) {
      console.log(error);
    }
  }

  //capitalizes first letter of the word
  function getCapitalized(word = "") {
    return word[0].toUpperCase() + word.substring(1);
  }

  
function maskNRIC(value?: string) {
  if(!value) return "";
  if (value.length <= 4) {
    return value;
  }

  const visiblePart = value.slice(-4);
  const maskedPart = "*".repeat(value.length - 4);

  return `${maskedPart}${visiblePart}`;
}

  return {
    requiredRule,
    emailRule,
    passwordRule,
    confirmPasswordRule,
    validateEmail,
    validEmail,
    validatePassword,
    back,
    debounce,
    insertBetween,
    getNameInitials,
    getDimensions,
    validateWord,
    getCountries,
    formatter,
    formatNumber,
    validateDate,
    minOneMonthAdvance,
    requireListRule,
    convertPermissionsToArray,
    redirect,
    computeTieredCost,
    getColorStatus,
    getStatusColor,
    getOrigin,
    search,
    formatDate,
    UTCToLocalTIme,
    formatNature,
    replaceMatch,
    setRouteParams,
    toOrdinal,
    formatDateISO8601,
    isValidBaseURL,
    formatCamelCaseToWords,
    calculateRemainingTime,
    formatTime,
    formatDateDDMMYYYYLocal,
    standardFormatDateTime,
    materialColors,
    getInitial,
    fileToBase64,
    getImage,
    standardFormatDate,
    getCapitalized,
    maskNRIC
  };
}
