import dayjs, { ConfigType, Dayjs } from "dayjs";
import { Uom } from "../api/settings/uom";
import {
  ListIterateeCustom,
  every,
  isArray,
  isNaN,
  isNull,
  isUndefined,
  take,
} from "lodash";
import { Box, BoxProps } from "@mui/material";

export const manhourFormatter = new Intl.NumberFormat("en-HK", {
  minimumFractionDigits: 2,
  maximumFractionDigits: 2,
});

export const moneyFormatter = new Intl.NumberFormat("en-HK", {
  style: "currency",
  currency: "HKD",
});

export const decimalFormatter = new Intl.NumberFormat("en-HK", {
  minimumFractionDigits: 2,
  maximumFractionDigits: 5,
});

/** Use for prices (e.g. market unit price): 2 decimal places only */
export const priceFormatter = new Intl.NumberFormat("en-HK", {
  minimumFractionDigits: 2,
  maximumFractionDigits: 2,
});

export const integerFormatter = new Intl.NumberFormat("en-HK", {});

/** 差異% 向零方向捨去小數，與後端 RoundingMode.DOWN 一致（-48.43 → -48） */
export function roundDownPercent(value: number): number {
  return Math.trunc(value);
}

/** 與 stocktakerecord DECIMAL(14,2) 整數部分上限一致 */
export const MAX_STOCK_TAKE_QTY = 999_999_999_999;
const MAX_STOCK_TAKE_QTY_DIGITS = 12;

/** 盤點數量輸入：僅數字，最多 12 位 */
export function sanitizeStockTakeQtyInput(value: string): string {
  return value.replace(/[^\d]/g, "").slice(0, MAX_STOCK_TAKE_QTY_DIGITS);
}

export type StockTakeQtyValidation =
  | { ok: true; qty: number }
  | { ok: false; errorKey: "Invalid QTY" | "Stock take qty exceeds maximum" };

export function validateStockTakeQtyString(
  value: string | undefined,
  options?: { allowEmpty?: boolean },
): StockTakeQtyValidation {
  const trimmed = (value ?? "").trim();
  if (!trimmed) {
    return options?.allowEmpty ? { ok: true, qty: 0 } : { ok: false, errorKey: "Invalid QTY" };
  }
  if (!/^\d+$/.test(trimmed)) {
    return { ok: false, errorKey: "Invalid QTY" };
  }
  if (trimmed.length > MAX_STOCK_TAKE_QTY_DIGITS) {
    return { ok: false, errorKey: "Stock take qty exceeds maximum" };
  }
  const qty = Number(trimmed);
  if (!Number.isFinite(qty) || qty > MAX_STOCK_TAKE_QTY) {
    return { ok: false, errorKey: "Stock take qty exceeds maximum" };
  }
  return { ok: true, qty };
}

export const INPUT_DATE_FORMAT = "YYYY-MM-DD";

export const OUTPUT_DATE_FORMAT = "YYYY-MM-DD";

/** Date and time for display, e.g. "YYYY-MM-DD HH:mm" */
export const OUTPUT_DATETIME_FORMAT = "YYYY-MM-DD HH:mm";

export const INPUT_TIME_FORMAT = "HH:mm:ss";

export const OUTPUT_TIME_FORMAT = "HH:mm:ss";

export const arrayToDayjs = (arr: ConfigType | (number | undefined)[], showTime: boolean = false) => {
  const isValidNumber = (
    item: ListIterateeCustom<number | undefined, boolean>,
  ): boolean => typeof item === "number" && !isNaN(item) && isFinite(item);

  let tempArr = arr;

  if (isArray(arr) && every(arr, isValidNumber) && arr.length >= 3) {
    // [year, month, day]
    // tempArr = take(arr, 3);
    tempArr = `${arr[0]?.toString().padStart(4, "0")}-${arr[1]?.toString().padStart(2, "0")}-${arr[2]?.toString().padStart(2, "0")}`;
    if (showTime) {
      // [year, month, day, hour, minute, second]
      tempArr += ` ${
        arr[3]?.toString().padStart(2, "0")}:${
          arr[4]?.toString().padStart(2, "0")}:${
            (arr[5] ?? 0)?.toString().padStart(2, "0")}`;
    }
  }

  return dayjs(tempArr as ConfigType);
};

/**
 * Backend `LocalDate` is often JSON `[year, month, day]` with month 1–12.
 * Do not pass that array to `dayjs(arr)` — it uses JS month index 0–11 and shifts the calendar month.
 */
export function requiredDeliveryDateToDayString(value: unknown): string {
  if (value == null) return "";
  if (Array.isArray(value) && value.length >= 3 && value.every((x) => typeof x === "number")) {
    return arrayToDayjs(value as number[]).format(OUTPUT_DATE_FORMAT);
  }
  return dayjs(value as string | number | Date).format(OUTPUT_DATE_FORMAT);
}

export const arrayToDateString = (arr: ConfigType | (number | undefined)[], format: "input"|"output" = "output") => {
  if (format == "output") {
    return arrayToDayjs(arr).format(OUTPUT_DATE_FORMAT);
  }
  else {
    return arrayToDayjs(arr).format(INPUT_DATE_FORMAT);
  }
};

export const arrayToDateTimeString = (arr: ConfigType | (number | undefined)[]) => {
  return arrayToDayjs(arr, true).format(`${OUTPUT_DATE_FORMAT} ${OUTPUT_TIME_FORMAT}`);
};

export const dateStringToDayjs = (date: string) => {
  // Format: YYYY/MM/DD
  return dayjs(date, OUTPUT_DATE_FORMAT);
};

export const dateTimeStringToDayjs = (dateTime: string) => {
  // Format: YYYY/MM/DD HH:mm:ss
  return dayjs(dateTime, `${OUTPUT_DATE_FORMAT} ${OUTPUT_TIME_FORMAT}`);
};

export const dayjsToDateString = (date: Dayjs, format: "input"|"output" = "output") => {
  if (format == "output") {
    return date.format(OUTPUT_DATE_FORMAT);
  } else {
    return date.format(INPUT_DATE_FORMAT);
  }
};

export const dayjsToDateTimeString = (date: Dayjs, format: "input"|"output" = "input") => {
  if (format == "input") {
    return date.format(`${INPUT_DATE_FORMAT}T${INPUT_TIME_FORMAT}`);
  }
  else {
    return date.format(`${OUTPUT_DATE_FORMAT}T${OUTPUT_TIME_FORMAT}`);
  }
};

export const dayjsToArray = (date: Dayjs) => {
    return [
      date.year(),
      date.month() + 1, // Months are 0-based in Day.js, so add 1
      date.date(),
      date.hour(), // (24-hour format)
      date.minute(),
      date.second(),
    ];
};

export const outputDateStringToInputDateString = (date: string) => {
  return dayjsToDateTimeString(dateStringToDayjs(date))
}

export const stockInLineStatusMap: { [status: string]: number } = {
  draft: 0,
  pending: 1,
  qc: 2,
  determine1: 3,
  determine2: 4,
  determine3: 5,
  receiving: 6,
  received: 7,
  completed: 8,
  rejected: 9,
};

export const stockOutLineStatusMap: { [status: string]: number } = {
  draft: 0,
  pending: 1, // waiting for qc
  determine1: 2, // waiting for qc
  "lot-change": 3, // waiting for qc
  // after qc = completed
  completed: 4,
  rejected: 5,
};

export const pickOrderStatusMap: { [status: string]: number } = {
  pending: 1,
  consolidated: 2,
  released: 3,
  completed: 4,
};

export const calculateWeight = (qty: number, uom: Uom) => {
  return qty * (uom.unit2Qty || 1) * (uom.unit3Qty || 1) * (uom.unit4Qty || 1);
};

export const returnWeightUnit = (uom: Uom) => {
  return uom.unit4 || uom.unit3 || uom.unit2 || uom.unit1;
};

/**
 * Formats departure time to HH:mm format
 * Handles array format [hours, minutes] from API and string formats
 */
export const formatDepartureTime = (time: string | number[] | String | Number | null | undefined): string => {
  if (!time) return "-";
  
  // Handle array format [hours, minutes] from API
  if (Array.isArray(time) && time.length >= 2) {
    const hours = time[0];
    const minutes = time[1];
    if (typeof hours === 'number' && typeof minutes === 'number' && 
        hours >= 0 && hours <= 23 && minutes >= 0 && minutes <= 59) {
      return `${hours.toString().padStart(2, "0")}:${minutes.toString().padStart(2, "0")}`;
    }
  }
  
  const timeStr = String(time).trim();
  if (!timeStr || timeStr === "-") return "-";
  
  // If already in HH:mm format, return as is
  if (/^\d{1,2}:\d{2}$/.test(timeStr)) {
    const [hours, minutes] = timeStr.split(":");
    return `${hours.padStart(2, "0")}:${minutes.padStart(2, "0")}`;
  }
  
  return timeStr;
};

/**
 * Normalizes store ID to display format (2F or 4F)
 */
export const normalizeStoreId = (storeId: string | number | String | Number | null | undefined): string => {
  if (!storeId) return "-";
  const storeIdStr = typeof storeId === 'string' || storeId instanceof String 
    ? String(storeId) 
    : String(storeId);
  if (storeIdStr === "2" || storeIdStr === "2F") return "2F";
  if (storeIdStr === "4" || storeIdStr === "4F") return "4F";
  return storeIdStr;
};