import dayjs from 'dayjs';
import isToday from 'dayjs/plugin/isToday';
import isYesterday from 'dayjs/plugin/isYesterday';

dayjs.extend(isToday);
dayjs.extend(isYesterday);

// Detect once at module load — the runtime locale doesn't change without a
// page reload. AM/PM systems set `hour12: true`; 24-hour systems leave it
// false/undefined. Older WebView builds may omit `hour12` entirely, so we
// fall back to the modern `hourCycle` field (h11/h12 = 12-hour, h23/h24 =
// 24-hour) before defaulting to 24-hour.
const detectSystemHour24 = (): boolean => {
  try {
    const opts = new Intl.DateTimeFormat(undefined, { hour: 'numeric' }).resolvedOptions();
    if (opts.hour12 === true) return false;
    if (opts.hour12 === false) return true;
    const cycle = (opts as { hourCycle?: string }).hourCycle;
    if (cycle === 'h11' || cycle === 'h12') return false;
    if (cycle === 'h23' || cycle === 'h24') return true;
    return true;
  } catch {
    return true;
  }
};

export const SYSTEM_HOUR_24: boolean = detectSystemHour24();

// Locale picks its own day-month-year order and separator: de-DE/ru-RU yield
// "13.05.2026", en-GB "13/05/2026", en-US "05/13/2026". Built once at module
// load — locale doesn't change without a page reload.
const dayMonYearFormatter: Pick<Intl.DateTimeFormat, 'format'> = (() => {
  try {
    return new Intl.DateTimeFormat(undefined, {
      day: '2-digit',
      month: '2-digit',
      year: 'numeric',
    });
  } catch {
    return { format: (date: Date) => dayjs(date).format('DD.MM.YYYY') };
  }
})();

export const today = (ts: number): boolean => dayjs(ts).isToday();

export const yesterday = (ts: number): boolean => dayjs(ts).isYesterday();

export const timeHour = (ts: number): string => dayjs(ts).format(SYSTEM_HOUR_24 ? 'HH' : 'hh');
export const timeMinute = (ts: number): string => dayjs(ts).format('mm');
export const timeAmPm = (ts: number): string => dayjs(ts).format('A');
export const timeDay = (ts: number): string => dayjs(ts).format('D');
export const timeMon = (ts: number): string => dayjs(ts).format('MMM');
export const timeMonth = (ts: number): string => dayjs(ts).format('MMMM');
export const timeYear = (ts: number): string => dayjs(ts).format('YYYY');

export const timeHourMinute = (ts: number): string =>
  dayjs(ts).format(SYSTEM_HOUR_24 ? 'HH:mm' : 'hh:mm A');

export const timeDayMonYear = (ts: number): string => dayMonYearFormatter.format(new Date(ts));

export const daysInMonth = (month: number, year: number): number =>
  dayjs(`${year}-${month}-1`).daysInMonth();

export const dateFor = (year: number, month: number, day: number): number =>
  dayjs(`${year}-${month}-${day}`).valueOf();

export const inSameDay = (ts1: number, ts2: number): boolean => {
  const dt1 = new Date(ts1);
  const dt2 = new Date(ts2);
  return (
    dt2.getFullYear() === dt1.getFullYear() &&
    dt2.getMonth() === dt1.getMonth() &&
    dt2.getDate() === dt1.getDate()
  );
};

export const minuteDifference = (ts1: number, ts2: number): number => {
  const dt1 = new Date(ts1);
  const dt2 = new Date(ts2);

  let diff = (dt2.getTime() - dt1.getTime()) / 1000;
  diff /= 60;
  return Math.abs(Math.round(diff));
};

export const hour24to12 = (hour24: number): number => {
  const h = hour24 % 12;

  if (h === 0) return 12;
  return h;
};

export const hour12to24 = (hour: number, pm: boolean): number => {
  if (hour === 12) {
    return pm ? 12 : 0;
  }
  return pm ? hour + 12 : hour;
};

export const secondsToMs = (seconds: number) => seconds * 1000;

export const minutesToMs = (minutes: number) => minutes * secondsToMs(60);

export const hoursToMs = (hour: number) => hour * minutesToMs(60);

export const daysToMs = (days: number) => days * hoursToMs(24);

export const getToday = () => {
  const nowTs = Date.now();
  const date = dayjs(nowTs);
  return dateFor(date.year(), date.month() + 1, date.date());
};

export const getYesterday = () => {
  const nowTs = Date.now() - daysToMs(1);
  const date = dayjs(nowTs);
  return dateFor(date.year(), date.month() + 1, date.date());
};
