import { Rating } from "./db/schema/property";
import { KeyboardEvent } from "react";

export function handleNumericKeyDown(event: KeyboardEvent<HTMLInputElement>) {
  /**
   * Allowing: Integers | Backspace | Tab | Delete | Left & Right arrow keys
   **/

  const regex = new RegExp(
    /(^\d*$)|(Backspace|Tab|Delete|ArrowLeft|ArrowRight|ArrowUp|ArrowDown)/
  );

  return !event.key.match(regex) && event.preventDefault();
}

export function convertDaysToWorkingWeeks(days: number | null) {
  if (days === null) {
    return "-";
  }

  const workingDaysPerWeek = 5;

  // Convert days to working weeks
  const workingWeeks = days / workingDaysPerWeek;

  // Determine the range
  let lowerBound = Math.floor(workingWeeks);
  let upperBound = Math.ceil(workingWeeks);

  // Adjust if the fraction is very small, you might not count it as a full extra week
  if (workingWeeks - lowerBound < 0.2) {
    upperBound = lowerBound;
  }

  if (lowerBound === 0 && upperBound === 1) {
    return "1 week";
  }

  if (lowerBound === 1 && upperBound === 1) {
    return "1-2 weeks";
  }

  // Format the output
  return lowerBound === upperBound
    ? `${lowerBound} weeks`
    : `${lowerBound}-${upperBound} weeks`;
}

export const getEpcColorClass = (letter: string) => {
  switch (letter.toUpperCase()) {
    case "A":
      return "bg-epc_a";
    case "B":
      return "bg-epc_b";
    case "C":
      return "bg-epc_c";
    case "D":
      return "bg-epc_d";
    case "E":
      return "bg-epc_e";
    case "F":
      return "bg-epc_f";
    case "G":
      return "bg-epc_g";
    default:
      return "bg-gray-500";
  }
};

/** Border + text colour classes for a transparent-background EPC badge */
export const getEpcAccentClasses = (letter: string) => {
  switch (letter.toUpperCase()) {
    case "A": return "border-epc_a text-epc_a";
    case "B": return "border-epc_b text-epc_b";
    case "C": return "border-epc_c text-epc_c";
    case "D": return "border-epc_d text-epc_d";
    case "E": return "border-epc_e text-epc_e";
    case "F": return "border-epc_f text-epc_f";
    case "G": return "border-epc_g text-epc_g";
    default:  return "border-slate-300 text-slate-400";
  }
};

export const getRating = (rating: number | null): Rating => {
  if (rating == null) {
    return "N/A";
  }

  if (![1, 2, 3, 4, 5].includes(rating)) {
    throw new Error("Rating should be between 1 and 5.");
  }

  const ratingMap: { [key in 1 | 2 | 3 | 4 | 5]: string } = {
    1: "Very poor",
    2: "Poor",
    3: "Average",
    4: "Good",
    5: "Very good",
  };

  return ratingMap[rating as 1 | 2 | 3 | 4 | 5] as Rating; // You can assert that rating is one of these values since you've already checked it
};

export const serializeBigInt = (_: any, value: any): string | any => {
  // Simple utility function to convert BigInts to strings with JSON.stringify
  return typeof value === "bigint" ? value.toString() : value;
};

export function sapToEpc(sapPoints: number | null): string {
  if (sapPoints === null) {
    return "Unknown";
  }

  if (sapPoints < 0) {
    throw new Error("SAP points should be above 0.");
  }

  if (sapPoints >= 92) {
    return "A";
  } else if (sapPoints >= 81) {
    return "B";
  } else if (sapPoints >= 69) {
    return "C";
  } else if (sapPoints >= 55) {
    return "D";
  } else if (sapPoints >= 39) {
    return "E";
  } else if (sapPoints >= 21) {
    return "F";
  } else {
    return "G";
  }
}

// Handles "D55" (new format) and "56" (legacy numeric-only format)
export function parsePreSap(raw: string | null | undefined): { letter: string; display: string } | null {
  if (!raw) return null;
  const match = raw.trim().match(/^([A-Za-z]?)(\d+)$/);
  if (!match) return null;
  const num = parseInt(match[2], 10);
  const letter = match[1] ? match[1].toUpperCase() : sapToEpc(num);
  if (letter === "Unknown") return null;
  return { letter, display: `${letter}${num}` };
}

export function formatDateTime(dateTimeString: string | Date): string {
  // Create a new Date object
  const dateTime = new Date(dateTimeString);

  // Get the various parts of the date
  const options: Intl.DateTimeFormatOptions = {
    year: "numeric",
    month: "long",
    day: "numeric",
    hour: "2-digit",
    minute: "2-digit",
  };
  return dateTime.toLocaleDateString("en-GB", options);
}

export function formatNumber(number: number): string {
  if (number === 0) return "0";

  if (number < 1) {
    return number.toFixed(2);
  }

  const suffixes = ["", "k", "m", "b", "t"];
  const suffixIndex = Math.floor(Math.log10(Math.abs(number)) / 3);

  if (suffixIndex >= suffixes.length) {
    return number.toString();
  }

  const scaledNumber = number / Math.pow(1000, suffixIndex);

  // Format the number to one decimal place
  let formatted = scaledNumber.toFixed(1);

  // Remove trailing '.0' if present
  if (formatted.endsWith(".0")) {
    formatted = formatted.slice(0, -2);
  }

  return formatted + suffixes[suffixIndex];
}

export function roundToDecimalPlaces(
  number: number,
  decimalPlaces: number
): number {
  const factor = 10 ** decimalPlaces;
  return Math.round(number * factor) / factor;
}
