export type DateInput = Date | string | number | null | undefined;

export const BANGKOK_TIME_ZONE = 'Asia/Bangkok';
export const GREGORIAN_CALENDAR = 'gregory';

const BANGKOK_OFFSET_MS = 7 * 60 * 60 * 1000;

interface BangkokDateParts {
  year: number;
  month: number;
  day: number;
  hour: number;
  minute: number;
  second: number;
}

function coerceDate(value: DateInput): Date | null {
  if (value === null || value === undefined || value === '') {
    return null;
  }

  const date = value instanceof Date ? new Date(value.getTime()) : new Date(value);
  return Number.isNaN(date.getTime()) ? null : date;
}

function pad2(value: number): string {
  return String(value).padStart(2, '0');
}

function getBangkokDateParts(value: DateInput): BangkokDateParts | null {
  const date = coerceDate(value);
  if (!date) {
    return null;
  }

  // Bangkok does not observe DST, so a fixed UTC+7 offset keeps formatting
  // deterministic across server and client runtimes.
  const bangkokDate = new Date(date.getTime() + BANGKOK_OFFSET_MS);

  return {
    year: bangkokDate.getUTCFullYear(),
    month: bangkokDate.getUTCMonth() + 1,
    day: bangkokDate.getUTCDate(),
    hour: bangkokDate.getUTCHours(),
    minute: bangkokDate.getUTCMinutes(),
    second: bangkokDate.getUTCSeconds()
  };
}

export function formatDate(value: DateInput): string {
  const parts = getBangkokDateParts(value);
  if (!parts) {
    return '';
  }

  return `${parts.year}-${pad2(parts.month)}-${pad2(parts.day)}`;
}

export function formatDateTime(value: DateInput): string {
  const parts = getBangkokDateParts(value);
  if (!parts) {
    return '';
  }

  return `${parts.year}-${pad2(parts.month)}-${pad2(parts.day)} ${pad2(parts.hour)}:${pad2(parts.minute)}:${pad2(parts.second)}`;
}

export function formatTime(value: DateInput): string {
  const parts = getBangkokDateParts(value);
  if (!parts) {
    return '';
  }

  return `${pad2(parts.hour)}:${pad2(parts.minute)}:${pad2(parts.second)}`;
}

export function formatMonth(value: DateInput): string {
  const parts = getBangkokDateParts(value);
  if (!parts) {
    return '';
  }

  return `${parts.year}-${pad2(parts.month)}`;
}

export function formatYear(value: DateInput): string {
  const parts = getBangkokDateParts(value);
  if (!parts) {
    return '';
  }

  return String(parts.year);
}

export const formatDateIso = formatDate;
