#!/usr/bin/env node
/**
 * ビルド時取得: JEPX スポット約定 CSV（Shift_JIS）→ 静的 JSON { [area]: { [date]: number[48] } }
 *
 * 使い方:
 *   node scripts/fetch-jepx.mjs [--days 90] [--out data/jepx-spot.json]
 *
 * 取込末尾で必ず検証する（コマ数 48・日付連続・価格レンジ 0〜999 円）。
 * 不合格なら何も書き込まず、非 0 exit する。
 * 注意: パッケージのビルド後（dist 生成後）に実行すること。
 */
import { mkdir, rename, writeFile } from "node:fs/promises";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { assertValidAreaSeries, parseJepxCsv, toAreaSeries } from "../dist/index.js";

const __dirname = path.dirname(fileURLToPath(import.meta.url));
const JEPX_URL_TEMPLATE = "https://www.jepx.jp/market/excel/spot_{year}.csv";

/* ---- 引数 ---- */
const args = process.argv.slice(2);
const argOf = (name, def) => {
  const i = args.indexOf(name);
  return i >= 0 && args[i + 1] != null ? args[i + 1] : def;
};
const days = Number(argOf("--days", "90"));
const outPath = path.resolve(argOf("--out", path.join(__dirname, "../data/jepx-spot.json")));
if (!Number.isInteger(days) || days < 1) {
  console.error(`--days が不正です: ${argOf("--days", "90")}`);
  process.exit(1);
}

/* ---- JST 日付ユーティリティ（このスクリプト内で完結） ---- */
const jstYmd = (d) =>
  new Intl.DateTimeFormat("sv-SE", { timeZone: "Asia/Tokyo", dateStyle: "short" }).format(d); // YYYY-MM-DD
const fiscalYearOf = (ymd) => {
  const [y, m] = ymd.split("-").map(Number);
  return m >= 4 ? y : y - 1;
};

async function main() {
  const now = new Date();
  const cutoffDate = jstYmd(new Date(now.getTime() - (days - 1) * 86400000));
  const today = jstYmd(now);
  const years = [...new Set([fiscalYearOf(cutoffDate), fiscalYearOf(today)])];

  // 取得（年度ファイル単位）。同一 date+slot は後勝ち
  const rowsByKey = new Map();
  let skippedTotal = 0;
  for (const year of years) {
    const url = JEPX_URL_TEMPLATE.replace("{year}", String(year));
    console.error(`fetch: ${url}`);
    const res = await fetch(url, { signal: AbortSignal.timeout(60000) });
    if (!res.ok) throw new Error(`HTTP ${res.status}: ${url}`);
    const text = new TextDecoder("shift_jis").decode(new Uint8Array(await res.arrayBuffer()));
    const { rows, skipped } = parseJepxCsv(text, { cutoffDate });
    skippedTotal += skipped;
    for (const r of rows) rowsByKey.set(`${r.date}#${r.slot}`, r);
    console.error(`  rows=${rows.length} skipped=${skipped}`);
  }
  if (rowsByKey.size === 0) throw new Error("有効行が 0 件です");

  // 静的 JSON 組み立て。48 コマ揃わない日付は末尾（公表途中）のみ許容し、それ以外は検証で落とす
  const { series, incompleteDates } = toAreaSeries([...rowsByKey.values()]);
  if (incompleteDates.length > 0)
    console.error(`48 コマ未満のため除外した日付: ${incompleteDates.join(", ")}`);

  // 検証ステップ（必須）: 件数 48・日付連続・価格レンジ 0〜999 円。不合格なら書き込まず非 0 exit
  assertValidAreaSeries(series, { minDays: 1, maxPriceYen: 999 });

  // 一時ファイルに書いてから rename（部分書き込みを残さない）
  await mkdir(path.dirname(outPath), { recursive: true });
  const tmp = `${outPath}.tmp`;
  await writeFile(tmp, JSON.stringify(series), "utf8");
  await rename(tmp, outPath);
  const dates = Object.keys(series.tokyo).sort();
  console.error(
    `wrote ${outPath}: ${dates.length} 日 (${dates[0]} .. ${dates[dates.length - 1]}), skipped=${skippedTotal}`,
  );
}

main().catch((e) => {
  console.error(`fetch-jepx failed: ${e instanceof Error ? e.message : e}`);
  process.exit(1);
});
