/**
 * D-Sec ログのモーダルの期間（ボタンと日付の範囲）→ 一覧の `from` / `to`（指示書AY 段階3。D23）。
 * 期待値の正は指示書AY §3 表2（`__tests__/presets.test.ts`）。
 *
 * ★純粋関数★。★実行環境のタイムゾーンに依存しない★（`toJstIso()` と `parseDate()` だけで組み立てる。表2 T10）。
 */
import { parseDate } from "@/lib/clean-logs/query";
import { toJstIso } from "@/lib/format/date";

export type DsLogPeriodPreset = "1h" | "3h" | "24h" | "all";

export interface DsLogPeriod {
  /** `+09:00` の ISO。`null` = 下限なし */
  from: string | null;
  /** `+09:00` の ISO。`null` = 上限なし */
  to: string | null;
}

const PRESET_HOURS: Record<Exclude<DsLogPeriodPreset, "all">, number> = {
  "1h": 1,
  "3h": 3,
  "24h": 24,
};

const HOUR_MS = 60 * 60 * 1000;
const DAY_MS = 24 * HOUR_MS;

/**
 * 期間ボタン（表2 T1〜T4・T10）。
 * ★`to` は付けない★（D23。制御盤の時計が進んでいても最新のファイルを外さない）。
 */
export function periodFromPreset(preset: DsLogPeriodPreset, now: Date): DsLogPeriod {
  if (preset === "all") return { from: null, to: null };
  return { from: toJstIso(new Date(now.getTime() - PRESET_HOURS[preset] * HOUR_MS)), to: null };
}

/**
 * 日付の範囲（`YYYY-MM-DD`。表2 T5〜T9）。★終了日を含む★（`to` は終了日の翌日 00:00 JST）。
 * 開始 ＞ 終了・存在しない日付は `null`（不正。画面は取得しない）。
 */
export function periodFromDates(startDate: string | null, endDate: string | null): DsLogPeriod | null {
  const start = startDate ? parseDate(startDate) : null;
  const end = endDate ? parseDate(endDate) : null;
  if ((startDate && !start) || (endDate && !end)) return null;
  if (start && end && start.getTime() > end.getTime()) return null;
  return {
    from: start ? toJstIso(start) : null,
    to: end ? toJstIso(new Date(end.getTime() + DAY_MS)) : null,
  };
}

/**
 * 日付の範囲の不正の種類（指示書BJ 表D・J12）。
 * ★両方とも読めて開始 ＞ 終了なら `"reversed"`★。片方 null は範囲未確定なので `null`。
 */
export function dateRangeError(
  start: string | null,
  end: string | null
): "reversed" | "invalid" | null {
  if (start === null || end === null) return null;
  const startDate = parseDate(start);
  const endDate = parseDate(end);
  if (startDate === null || endDate === null) return "invalid";
  if (startDate.getTime() > endDate.getTime()) return "reversed";
  return null;
}
