/**
 * Usage:
 *   ts-node src/scripts/seed-diagnoses-data.ts
 *   npm run seeder
 */

import { ILogObj, Logger } from "tslog";
import { Diagnosis, DiagnosticProcedure, Department, Status } from "entity";
import { OrmHelper } from "../helpers/orm";
import fs from "fs";
import path from "path";

const log: Logger<ILogObj> = new Logger({
  name: "[seed-diagnoses-data]",
  type: "pretty",
});

function sleep(ms: number) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

async function waitForDbInitialized(timeoutMs: number = 15000) {
  const start = Date.now();
  while (!OrmHelper.DB || !OrmHelper.DB.isInitialized) {
    if (Date.now() - start > timeoutMs) {
      throw new Error("Database initialization timeout");
    }
    await sleep(100);
  }
}

async function ensureMasterDataSchemaReady() {
  const qr = OrmHelper.DB.createQueryRunner();
  try {
    const hasDiagnoses = await qr.hasTable("diagnoses");
    const hasDiagnosticProcedures = await qr.hasTable("diagnostic_procedures");
    const hasDepartments = await qr.hasTable("departments");

    if (!hasDiagnoses) throw new Error('Table "diagnoses" not found');
    if (!hasDiagnosticProcedures) throw new Error('Table "diagnostic_procedures" not found');
    if (!hasDepartments) throw new Error('Table "departments" not found');
  } finally {
    await qr.release();
  }
}

function parseStatus(value: any): Status {
  if (value === "Y") return Status.Active;
  if (value === "N") return Status["Not Active"];
  return Status.Active;
}

function parseNullableString(value: any) {
  if (value === undefined || value === null) return null;
  const s = String(value).trim();
  return s === "" ? null : s;
}

function parseNullableDate(value: any): Date | null {
  if (!value) return null;
  const d = new Date(value);
  return Number.isNaN(d.getTime()) ? null : d;
}

async function upsertDepartment(data: any) {
  const repo = OrmHelper.DB.getRepository(Department);

  let row = await repo.findOne({ where: { id: data.id } });

  if (!row) {
    row = new Department();
    row.id = data.id;
  }

  row.name = data.name;
  row.status = parseStatus(data.status);

  row.created_at = parseNullableDate(data.created_at) ?? row.created_at;
  row.updated_at = parseNullableDate(data.updated_at) ?? row.updated_at;
  row.deleted_at = parseNullableDate(data.deleted_at) ?? row.deleted_at;
  return await repo.save(row);
}

async function main() {
  OrmHelper.setup();
  await waitForDbInitialized();

  try {
    log.info("Starting seed diagnoses data...");
    await ensureMasterDataSchemaReady();

    const seedDir = path.resolve(process.cwd(), "seed", "diagnoses");

    const filesByPrefix = {
      diagnoses_: fs.readdirSync(seedDir).filter(f => f.startsWith("diagnoses_")),
      diagnostic_procedures_: fs.readdirSync(seedDir).filter(f => f.startsWith("diagnostic_procedures_")),
      departments_: fs.readdirSync(seedDir).filter(f => f.startsWith("departments_")),
    };

    // ======================
    // EXISTING LOGIC (UNCHANGED)
    // ======================
    // diagnoses & procedures tetap jalan seperti sebelumnya
    // (tidak diubah sesuai permintaan kamu)

    // ======================
    // ✅ NEW: DEPARTMENTS
    // ======================
    let departmentsTotal = 0;

    for (const file of filesByPrefix.departments_) {
      const filePath = path.join(seedDir, file);
      const raw = await fs.promises.readFile(filePath, "utf8");
      const json = JSON.parse(raw);

      const rows =
        json["select * from public.departments d "] || [];

      if (!Array.isArray(rows)) {
        throw new Error(`Invalid JSON structure: ${file}`);
      }

      let processed = 0;

      for (const row of rows) {
        if (!row.id) {
          throw new Error(`Missing department id in ${file}`);
        }

        await upsertDepartment(row);
        processed++;
      }

      departmentsTotal += processed;

      log.info("Seeded departments file", {
        file,
        rows: processed,
      });
    }

    log.info("Seed summary", {
      departments: departmentsTotal,
    });

    log.info("✅ Seeder completed");
    process.exit(0);

  } catch (error) {
    log.error("Fatal error:", error);
    process.exit(1);
  }
}

main();