/**
 * 表示用の日付・時刻整形。
 * APIの日時は ISO8601（JST, +09:00）。タイムゾーン変換せず文字列から切り出す。
 */
import { DB_DATETIME_OFFSET_MINUTES } from "@/lib/config";

/** 2026-08-27T02:00:00+09:00 → 8/27（モックの日付列） */
export function formatMd(iso: string): string {
  const month = Number.parseInt(iso.slice(5, 7), 10);
  const day = Number.parseInt(iso.slice(8, 10), 10);
  return `${month}/${day}`;
}

/** 2026-08-27T02:00:00+09:00 → 02:00 */
export function formatHm(iso: string): string {
  return iso.slice(11, 16);
}

/** JSTの今日を YYYY-MM-DD で返す */
export function todayJst(): string {
  return new Intl.DateTimeFormat("en-CA", {
    timeZone: "Asia/Tokyo",
    year: "numeric",
    month: "2-digit",
    day: "2-digit",
  }).format(new Date());
}

/**
 * Prisma から読んだ `Date`（DBの DATETIME/TIMESTAMP）を ISO8601（JST, +09:00）文字列にする
 * （指示書P 段階2/3）。
 *
 * `Date` は常にUTC起点の絶対時刻を保持するので、`Intl` 等の環境依存タイムゾーンに頼らず、
 * UTCに9時間を足してから UTC の getter で文字列を組み立てる（実行環境のタイムゾーンに
 * 依存しない。テストが CI 環境のタイムゾーンで揺れないようにするため）。
 */
export function toJstIso(date: Date): string {
  const jst = new Date(date.getTime() + 9 * 60 * 60 * 1000);
  const y = jst.getUTCFullYear();
  const m = String(jst.getUTCMonth() + 1).padStart(2, "0");
  const d = String(jst.getUTCDate()).padStart(2, "0");
  const hh = String(jst.getUTCHours()).padStart(2, "0");
  const mm = String(jst.getUTCMinutes()).padStart(2, "0");
  const ss = String(jst.getUTCSeconds()).padStart(2, "0");
  return `${y}-${m}-${d}T${hh}:${mm}:${ss}+09:00`;
}

/**
 * Prisma（`@prisma/adapter-mariadb`）から出てきた `Date` を「真の瞬間」に直す。
 *
 * ★なぜ要るのか★:
 *   DB の DATETIME には ★日本時間の壁時計値★ が入っている（TeamWorks 第8回 A2。指示書Y）。
 *   ところがアダプタは ``new Date(`${value}Z`)`` で ★UTC とみなして★ `Date` にする
 *   （`node_modules/@prisma/adapter-mariadb/dist/index.js` の `mapRow()`）。
 *   ★この挙動は設定で変更できない★ — 接続文字列の `timezone` も効かない
 *   （アダプタが `dateStrings: true` でドライバの変換を迂回しているため）。
 *   結果、返ってくる `Date` は ★真の瞬間より9時間先★ を指している。
 *
 * ★補正しないと何が起きるか★:
 *   表示が9時間進むだけでなく、`isFutureSchedule()`（`lib/db/clean-log-mapping.ts`）の
 *   実時刻との比較が狂い、★深夜2時の清掃が翌朝の確認時刻でも「まだ未来」と判定されて
 *   画面から消える★（`CLAUDE.md` §1 の「翌朝確認型」の運用を直撃する）。
 *
 * ★使い方★: Prisma から出た日時は、既存の処理に渡す前に必ずこれを通す。
 *   `toJstIso()` と `isFutureSchedule()` は変更しない（入力が正しくなれば直る）。
 */
export function fromDbJst(date: Date): Date {
  return new Date(date.getTime() - DB_DATETIME_OFFSET_MINUTES * 60_000);
}

/**
 * `fromDbJst()` の逆。「真の瞬間」を、DB に書きたい壁時計値として渡せる `Date` にする。
 *
 * ★なぜ要るのか★: アダプタの書き込み側（`formatDateTime()`）は `getUTC*` で文字列を組み立てる。
 *   つまり「DB に書きたい壁時計値を UTC のフィールドに載せた `Date`」を渡す必要がある。
 *
 * ★消費者★: `scripts/seed-local-db.ts` と、アプリの書き込み `lib/db/robot-error-write.ts`
 *   （書き込み許可4カラム `status` / `comment` / `responded_at` / `resolved_at` の日時2カラム。D-042 / 指示書AT）。
 *   ★メインDBに日時を書くときは必ずこれを通すこと★（付け忘れはガードテスト
 *   `lib/db/__tests__/robot-error-write-sql.test.ts` が検出する）
 */
export function toDbJst(date: Date): Date {
  return new Date(date.getTime() + DB_DATETIME_OFFSET_MINUTES * 60_000);
}

/**
 * Prisma から出た日時 → ISO8601（JST, +09:00）文字列。
 *
 * ★`toJstIso(fromDbJst(date))` の合成★ — ★★この2段を1つの式に潰さないこと★★。
 *   潰すと「DB のタイムゾーン」という設定値が式から消え、`lib/config` を変えても効かなくなる。
 *
 * ★性質★: 戻り値の日時の桁は ★DB の生値そのもの★ になる。
 *   （DB が `2026-09-11 02:00:00` なら `"2026-09-11T02:00:00+09:00"`）
 *   ★これが「直った」ことの判定基準★ — DB の生値と画面の表示が一致すること。
 */
export function jstIsoFromDb(date: Date): string {
  return toJstIso(fromDbJst(date));
}

/** YYYY-MM-DD 同士の日数（両端含む）。不正なら null */
export function inclusiveDayCount(from: string, to: string): number | null {
  if (!/^\d{4}-\d{2}-\d{2}$/.test(from) || !/^\d{4}-\d{2}-\d{2}$/.test(to)) {
    return null;
  }
  const start = Date.parse(`${from}T00:00:00+09:00`);
  const end = Date.parse(`${to}T00:00:00+09:00`);
  if (Number.isNaN(start) || Number.isNaN(end)) return null;
  return Math.floor((end - start) / 86_400_000) + 1;
}
