/**
 * Canlı YÖK Atlas API'sinden program detay verilerini çekip DB'ye işler:
 *
 * 1. Kontenjan türü kırılımı (son yerleştirme yılı, ör. 2025):
 *    Genel / Okul Birincisi / Şehit-Gazi / Deprem / 34 Yaş Üstü Kadın
 *    için kontenjan + yerleşen. Kaynak: POST /api/tercih-kilavuz/search
 *    (gk1/gkY1, obk1/obkY1, sgy1/sgyY1, dprm1/dprmY1, y34_1/y34Y1 —
 *    "1" son yerleştirme yılı demek; kayıttaki `yil` kılavuz yılıdır,
 *    veri yılı = yil - 1).
 *
 * 2. Yerleşen son kişinin netleri (yıl bazında, tüm puan türleri):
 *    Kaynak: POST /api/netler/search → `netler` tablosu.
 *
 * Not: YÖK Atlas 2026'da SPA'ya geçti; eski content/lisans-dynamic/*.php
 * panelleri (ve onlarla birlikte kadın-erkek dağılımı) yayından kalktı.
 * Cinsiyet verisi yeni API'lerin hiçbirinde yok.
 *
 * Kullanım: npx tsx scripts/detay.ts
 */
import path from "node:path";
import Database from "better-sqlite3";

const KILAVUZ_API = "https://yokatlas.yok.gov.tr/api/tercih-kilavuz/search";
const NETLER_API = "https://yokatlas.yok.gov.tr/api/netler/search";
const PAGE_SIZE = 500;
const DELAY_MS = 300;

type KilavuzRecord = {
  kilavuzKodu: number;
  eskiKilavuzKodu?: number | null;
  yil: number;
  gk1?: number | null;
  gkY1?: number | null;
  obk1?: number | null;
  obkY1?: number | null;
  sgy1?: number | null;
  sgyY1?: number | null;
  dprm1?: number | null;
  dprmY1?: number | null;
  y34_1?: number | null;
  y34Y1?: number | null;
};

type NetlerRecord = {
  kilavuzKodu: number;
  yil: number;
  puanTuru: string | null;
  tabanPuan?: number | null;
  obp?: number | null;
  katsayi?: number | null;
  tytTrkNet?: number | null;
  tytSosNet?: number | null;
  tytMatNet?: number | null;
  tytFenNet?: number | null;
  aytMatNet?: number | null;
  aytFizNet?: number | null;
  aytKimNet?: number | null;
  aytBioNet?: number | null;
  aytTdeNet?: number | null;
  aytTrh1Net?: number | null;
  aytCog1Net?: number | null;
  aytTrh2Net?: number | null;
  aytCog2Net?: number | null;
  aytDinNet?: number | null;
  aytFelNet?: number | null;
  ydtYdilNet?: number | null;
};

type ApiPage<T> = { content: T[]; totalPages: number; totalElements: number };

const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));

async function fetchPage<T>(api: string, page: number): Promise<ApiPage<T>> {
  const res = await fetch(api, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      filters: {},
      page,
      size: PAGE_SIZE,
      sortBy: "kilavuzKodu",
      direction: "ASC",
    }),
  });
  if (!res.ok) throw new Error(`${api} ${res.status} (sayfa ${page})`);
  return (await res.json()) as ApiPage<T>;
}

function num(v: unknown): number | null {
  return typeof v === "number" && Number.isFinite(v) ? v : null;
}

const NET_COLS = [
  "puanTuru",
  "tabanPuan",
  "obp",
  "katsayi",
  "tytTrkNet",
  "tytSosNet",
  "tytMatNet",
  "tytFenNet",
  "aytMatNet",
  "aytFizNet",
  "aytKimNet",
  "aytBioNet",
  "aytTdeNet",
  "aytTrh1Net",
  "aytCog1Net",
  "aytTrh2Net",
  "aytCog2Net",
  "aytDinNet",
  "aytFelNet",
  "ydtYdilNet",
] as const;

async function main() {
  const db = new Database(path.join(process.cwd(), "data", "yokatlas.db"));
  db.pragma("journal_mode = WAL");

  // ── 1. Kontenjan türü kırılımı ─────────────────────────────────────────
  const first = await fetchPage<KilavuzRecord>(KILAVUZ_API, 0);
  // API kaydındaki yil kılavuz yılı; "1" ekli alanlar bir önceki
  // yerleştirme dönemine ait (2026 kılavuzu → 2025 verisi)
  const veriYili = first.content[0].yil - 1;

  const kontCols = [
    `gk${veriYili}`,
    `gkY${veriYili}`,
    `obk${veriYili}`,
    `obkY${veriYili}`,
    `sgy${veriYili}`,
    `sgyY${veriYili}`,
    `dprm${veriYili}`,
    `dprmY${veriYili}`,
    `y34k${veriYili}`,
    `y34kY${veriYili}`,
  ];
  const mevcut = new Set(
    (db.prepare("PRAGMA table_info(programs)").all() as { name: string }[]).map(
      (c) => c.name
    )
  );
  for (const col of kontCols) {
    if (!mevcut.has(col)) {
      db.exec(`ALTER TABLE programs ADD COLUMN ${col} INTEGER`);
    }
  }

  const updateKont = db.prepare(`
    UPDATE programs SET ${kontCols.map((c) => `${c} = ?`).join(", ")}
    WHERE id = ?
  `);
  const exists = db.prepare("SELECT 1 FROM programs WHERE id = ?");

  // Kılavuz kodu yıllar arasında değişebiliyor (eskiKilavuzKodu); netler
  // API'si yeni kodla döndüğü için eşleşen DB id'sini haritada tutuyoruz.
  const dbId = new Map<number, string>();
  let kontUpdated = 0;
  let kontMissing = 0;

  const processKilavuz = db.transaction((records: KilavuzRecord[]) => {
    for (const r of records) {
      if (!r.kilavuzKodu) continue;
      let id = String(r.kilavuzKodu);
      if (!exists.get(id)) {
        const eski = r.eskiKilavuzKodu ? String(r.eskiKilavuzKodu) : null;
        if (eski && exists.get(eski)) {
          id = eski;
        } else {
          kontMissing++;
          continue;
        }
      }
      dbId.set(r.kilavuzKodu, id);
      updateKont.run(
        num(r.gk1),
        num(r.gkY1),
        num(r.obk1),
        num(r.obkY1),
        num(r.sgy1),
        num(r.sgyY1),
        num(r.dprm1),
        num(r.dprmY1),
        num(r.y34_1),
        num(r.y34Y1),
        id
      );
      kontUpdated++;
    }
  });

  console.log(
    `Kontenjan kırılımı (${veriYili}): ${first.totalElements} kayıt, ${first.totalPages} sayfa…`
  );
  processKilavuz(first.content);
  for (let p = 1; p < first.totalPages; p++) {
    await sleep(DELAY_MS);
    processKilavuz((await fetchPage<KilavuzRecord>(KILAVUZ_API, p)).content);
    process.stdout.write(`\rkontenjan sayfa ${p + 1}/${first.totalPages}`);
  }
  console.log(
    `\nKontenjan kırılımı: ${kontUpdated} güncellendi, ${kontMissing} DB'de yok`
  );

  // ── 2. Yerleşen son kişinin netleri ────────────────────────────────────
  db.exec(`
    CREATE TABLE IF NOT EXISTS netler (
      program_id TEXT NOT NULL,
      yil INTEGER NOT NULL,
      ${NET_COLS.map((c) => `${c} ${c === "puanTuru" ? "TEXT" : "REAL"}`).join(
        ",\n      "
      )},
      PRIMARY KEY (program_id, yil)
    );
  `);

  const insertNet = db.prepare(`
    INSERT OR REPLACE INTO netler (program_id, yil, ${NET_COLS.join(", ")})
    VALUES (${["?", "?", ...NET_COLS.map(() => "?")].join(", ")})
  `);

  let netRows = 0;
  const processNetler = db.transaction((records: NetlerRecord[]) => {
    for (const r of records) {
      if (!r.kilavuzKodu || !r.yil) continue;
      const id = dbId.get(r.kilavuzKodu) ?? String(r.kilavuzKodu);
      insertNet.run(
        id,
        r.yil,
        r.puanTuru?.trim() ?? null,
        ...NET_COLS.slice(1).map((c) => num(r[c as keyof NetlerRecord]))
      );
      netRows++;
    }
  });

  const netFirst = await fetchPage<NetlerRecord>(NETLER_API, 0);
  console.log(
    `Netler: ${netFirst.totalElements} kayıt, ${netFirst.totalPages} sayfa…`
  );
  processNetler(netFirst.content);
  for (let p = 1; p < netFirst.totalPages; p++) {
    await sleep(DELAY_MS);
    processNetler((await fetchPage<NetlerRecord>(NETLER_API, p)).content);
    process.stdout.write(`\rnetler sayfa ${p + 1}/${netFirst.totalPages}`);
  }
  console.log(`\nNetler: ${netRows} satır yazıldı`);

  const ozet = db
    .prepare(
      `SELECT
         (SELECT COUNT(*) FROM programs WHERE gkY${veriYili} IS NOT NULL) AS kontlu,
         (SELECT COUNT(*) FROM netler) AS net,
         (SELECT COUNT(DISTINCT program_id) FROM netler) AS netli_program`
    )
    .get() as { kontlu: number; net: number; netli_program: number };
  console.log(
    `Özet → kontenjan kırılımı olan program: ${ozet.kontlu}, ` +
      `net satırı: ${ozet.net} (${ozet.netli_program} program)`
  );
  db.close();
}

main().catch((err) => {
  console.error(err);
  process.exit(1);
});
