export const DEFAULT_TIME_ZONE = "Asia/Shanghai";
export const TIME_ZONE_STORAGE_KEY = "hyapp-admin.display-time-zone";
export const TIME_ZONE_OPTIONS = [
  { label: "北京时间", value: "Asia/Shanghai" },
  { label: "UTC", value: "UTC" }
];

const dateFormatterCache = new Map();
const dateTimeFormatterCache = new Map();

export function todayRange(timeZone = DEFAULT_TIME_ZONE) {
  const today = dateInputValueInTimeZone(new Date(), timeZone);
  return { end: today, endTime: "23:59:59", start: today, startTime: "00:00:00" };
}

export function lastDaysRange(days, timeZone = DEFAULT_TIME_ZONE) {
  const end = dateInputValueInTimeZone(new Date(), timeZone);
  const start = shiftDateValue(end, 1 - Number(days || 1));
  return { end, endTime: "23:59:59", start, startTime: "00:00:00" };
}

export function thisMonthRange(timeZone = DEFAULT_TIME_ZONE) {
  const end = dateInputValueInTimeZone(new Date(), timeZone);
  const [year, month] = end.split("-");
  return { end, endTime: "23:59:59", start: `${year}-${month}-01`, startTime: "00:00:00" };
}

export function normalizeTimeZone(value) {
  return TIME_ZONE_OPTIONS.some((option) => option.value === value) ? value : DEFAULT_TIME_ZONE;
}

export function getTimeZoneLabel(value) {
  return TIME_ZONE_OPTIONS.find((option) => option.value === value)?.label || "北京时间";
}

export function readStoredTimeZone(storage = globalThis.localStorage) {
  try {
    return normalizeTimeZone(storage?.getItem(TIME_ZONE_STORAGE_KEY));
  } catch {
    return DEFAULT_TIME_ZONE;
  }
}

export function writeStoredTimeZone(value, storage = globalThis.localStorage) {
  const normalized = normalizeTimeZone(value);
  try {
    storage?.setItem(TIME_ZONE_STORAGE_KEY, normalized);
  } catch {
    // 偏好写入失败不能影响本次大屏筛选。
  }
  return normalized;
}

export function startOfDay(value) {
  return value ? new Date(`${value}T00:00:00`).getTime() : "";
}

export function endOfDay(value) {
  return value ? new Date(`${value}T23:59:59`).getTime() : "";
}

export function rangeEndMs(range, timeZone = DEFAULT_TIME_ZONE) {
  return dateTimeMs(range?.end, range?.endTime || "23:59:59", timeZone);
}

// Finance/Statistics 查询统一使用 [start_ms, end_ms)；筛选器只有秒精度，
// 因此把可见结束秒推进 1 秒作为排他上界，避免漏掉结束日 23:59:59.xxx 的账单。
export function rangeExclusiveEndMs(range, timeZone = DEFAULT_TIME_ZONE) {
  const endMs = rangeEndMs(range, timeZone);
  return endMs === "" ? "" : Number(endMs) + 1000;
}

export function rangeStartMs(range, timeZone = DEFAULT_TIME_ZONE) {
  return dateTimeMs(range?.start, range?.startTime || "00:00:00", timeZone);
}

export function formatDateTime(value, timeZone = DEFAULT_TIME_ZONE) {
  const millis = Number(value) || Date.now();
  const parts = Object.fromEntries(
    getDateTimeFormatter(normalizeTimeZone(timeZone))
      .formatToParts(millis)
      .filter((part) => part.type !== "literal")
      .map((part) => [part.type, part.value])
  );
  return `${parts.year}-${parts.month}-${parts.day} ${parts.hour}:${parts.minute}`;
}

export function sameRange(left, right) {
  return left?.start === right?.start && left?.end === right?.end && normalizeTime(left?.startTime || "00:00:00") === normalizeTime(right?.startTime || "00:00:00") && normalizeTime(left?.endTime || "23:59:59") === normalizeTime(right?.endTime || "23:59:59");
}

function dateTimeMs(dateValue, timeValue, timeZone) {
  if (!dateValue) {
    return "";
  }
  const suffix = normalizeTimeZone(timeZone) === "UTC" ? "Z" : "+08:00";
  return Date.parse(`${dateValue}T${normalizeTime(timeValue)}${suffix}`);
}

function normalizeTime(value) {
  const parts = String(value || "00:00:00").split(":");
  return `${pad2(parts[0] || 0)}:${pad2(parts[1] || 0)}:${pad2(parts[2] || 0)}`;
}

function dateInputValueInTimeZone(date, timeZone) {
  const parts = Object.fromEntries(
    getDateFormatter(normalizeTimeZone(timeZone))
      .formatToParts(date)
      .filter((part) => part.type !== "literal")
      .map((part) => [part.type, part.value])
  );
  return `${parts.year}-${parts.month}-${parts.day}`;
}

function shiftDateValue(value, days) {
  const [year, month, day] = String(value).split("-").map(Number);
  const date = new Date(Date.UTC(year || 1970, (month || 1) - 1, (day || 1) + days));
  return `${date.getUTCFullYear()}-${pad2(date.getUTCMonth() + 1)}-${pad2(date.getUTCDate())}`;
}

function getDateFormatter(timeZone) {
  if (!dateFormatterCache.has(timeZone)) {
    dateFormatterCache.set(
      timeZone,
      new Intl.DateTimeFormat("en-CA", {
        day: "2-digit",
        month: "2-digit",
        timeZone,
        year: "numeric"
      })
    );
  }
  return dateFormatterCache.get(timeZone);
}

function getDateTimeFormatter(timeZone) {
  if (!dateTimeFormatterCache.has(timeZone)) {
    dateTimeFormatterCache.set(
      timeZone,
      new Intl.DateTimeFormat("en-CA", {
        day: "2-digit",
        hour: "2-digit",
        hourCycle: "h23",
        minute: "2-digit",
        month: "2-digit",
        timeZone,
        year: "numeric"
      })
    );
  }
  return dateTimeFormatterCache.get(timeZone);
}

function pad2(value) {
  return String(value).padStart(2, "0");
}
