import DateObject from "react-date-object";
import persian from "react-date-object/calendars/persian";
import persian_fa from "react-date-object/locales/persian_fa";
import gregorian from "react-date-object/calendars/gregorian";
import gregorian_en from "react-date-object/locales/gregorian_en";

export type JalaliMonthRange = {
  title: string;
  from: string;
  to: string;
  year: number;
  month: number;
};

export function jalaliMonth(now = new Date()): JalaliMonthRange {
  const persianNow = new DateObject({
    date: gregorianIsoFromDate(now),
    format: "YYYY-MM-DD",
    calendar: gregorian,
    locale: gregorian_en,
  }).convert(persian, persian_fa);

  return jalaliMonthFromParts(persianNow.year, persianNow.month.number);
}

export function shiftJalaliMonth(range: JalaliMonthRange, delta: number): JalaliMonthRange {
  const shifted = new DateObject({
    year: range.year,
    month: range.month,
    day: 1,
    calendar: persian,
    locale: persian_fa,
  }).add(delta, "month");

  return jalaliMonthFromParts(shifted.year, shifted.month.number);
}

export function jalaliMonthFromParts(year: number, month: number): JalaliMonthRange {
  const start = new DateObject({
    year,
    month,
    day: 1,
    calendar: persian,
    locale: persian_fa,
  });
  const end = new DateObject(start).toLastOfMonth();

  return {
    title: start.format("MMMM YYYY"),
    from: toGregorianIso(start),
    to: toGregorianIso(end),
    year: start.year,
    month: start.month.number,
  };
}

export function toGregorianIso(date: DateObject): string {
  return new DateObject(date).convert(gregorian, gregorian_en).format("YYYY-MM-DD");
}

export function gregorianIsoFromDate(date: Date): string {
  const y = date.getFullYear();
  const m = String(date.getMonth() + 1).padStart(2, "0");
  const d = String(date.getDate()).padStart(2, "0");
  return `${y}-${m}-${d}`;
}

export function toJalaliDateObject(input?: string | Date | null): DateObject | null {
  const iso = typeof input === "string"
    ? input.slice(0, 10)
    : input instanceof Date
      ? gregorianIsoFromDate(input)
      : "";
  if (!/^\d{4}-\d{2}-\d{2}$/.test(iso)) {
    return null;
  }

  return new DateObject({
    date: iso,
    format: "YYYY-MM-DD",
    calendar: gregorian,
    locale: gregorian_en,
  }).convert(persian, persian_fa);
}

export function formatJalaliDate(input?: string | Date | null, empty = "—"): string {
  const date = toJalaliDateObject(input);
  return date ? date.format("YYYY/MM/DD") : empty;
}

export function formatJalaliDateTime(input?: string | Date | null, empty = "—"): string {
  if (!input) return empty;
  const date = input instanceof Date ? input : new Date(input);
  if (Number.isNaN(date.getTime())) return formatJalaliDate(input, empty);
  return new DateObject(date).convert(persian, persian_fa).format("YYYY/MM/DD HH:mm");
}

export function jalaliDayNumber(input?: string | Date | null): string {
  return toJalaliDateObject(input)?.format("D") ?? "";
}

export function addGregorianDays(iso: string, days: number): string {
  const d = new Date(`${iso.slice(0, 10)}T00:00:00`);
  d.setDate(d.getDate() + days);
  const y = d.getFullYear();
  const m = String(d.getMonth() + 1).padStart(2, "0");
  const day = String(d.getDate()).padStart(2, "0");
  return `${y}-${m}-${day}`;
}
