/**
 * Self-test wallets read cutover (WALLETS_DATABASE=mysql).
 */
import fs from "fs";
import path from "path";
import mysql from "mysql2/promise";

function loadEnv() {
  const t = fs.readFileSync(path.join(process.cwd(), ".env"), "utf8");
  for (const line of t.split(/\r?\n/)) {
    const s = line.trim();
    if (!s || s.startsWith("#")) continue;
    const eq = s.indexOf("=");
    if (eq <= 0) continue;
    const k = s.slice(0, eq).trim();
    let v = s.slice(eq + 1).trim();
    if (
      (v.startsWith('"') && v.endsWith('"')) ||
      (v.startsWith("'") && v.endsWith("'"))
    )
      v = v.slice(1, -1);
    process.env[k] = v;
  }
}

function nearly(a: number, b: number) {
  return Math.abs(Number(a) - Number(b)) < 0.02;
}

async function main() {
  loadEnv();
  const port = process.env.PORT || "4000";
  const base = `http://127.0.0.1:${port}`;
  const results: { name: string; pass: boolean; detail: string }[] = [];
  const check = (name: string, pass: boolean, detail: string) => {
    results.push({ name, pass, detail });
    console.log(`${pass ? "PASS" : "FAIL"}  ${name} — ${detail}`);
  };

  check(
    "env_wallets_mysql",
    (process.env.WALLETS_DATABASE || "").toLowerCase() === "mysql",
    `WALLETS_DATABASE=${process.env.WALLETS_DATABASE}`,
  );

  const login = await fetch(`${base}/api/auth/login`, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ email: "admin@safarlibya.com", password: "19992000" }),
  });
  const auth: any = await login.json().catch(() => null);
  check("login", !!auth?.accessToken, `status=${login.status}`);
  if (!auth?.accessToken) {
    console.log("\nSUMMARY wallets-read: FAIL");
    process.exit(1);
  }
  const headers = {
    Authorization: `Bearer ${auth.accessToken}`,
    "Content-Type": "application/json",
  };
  const userId = auth.user?.id;

  const getBefore = await fetch(`${base}/api/wallet`, { headers });
  const beforeBody: any = await getBefore.json().catch(() => null);
  check(
    "get_wallet_mysql",
    getBefore.status === 200 && beforeBody?._db === "mysql",
    `status=${getBefore.status} _db=${beforeBody?._db} bal=${beforeBody?.wallet?.balanceLyd}`,
  );

  const topupsList = await fetch(`${base}/api/wallet/topups`, { headers });
  const topupsBody: any = await topupsList.json().catch(() => null);
  check(
    "list_topups_mysql",
    topupsList.status === 200 && topupsBody?._db === "mysql",
    `status=${topupsList.status} _db=${topupsBody?._db}`,
  );

  const adminWallets = await fetch(`${base}/api/admin/wallets`, { headers });
  const adminWalletsBody: any = await adminWallets.json().catch(() => null);
  check(
    "admin_list_wallets_mysql",
    adminWallets.status === 200 && adminWalletsBody?._db === "mysql",
    `status=${adminWallets.status} _db=${adminWalletsBody?._db} count=${adminWalletsBody?.wallets?.length}`,
  );

  const marker = `wallets-read-${Date.now()}`;
  const topup = await fetch(`${base}/api/wallet/topups`, {
    method: "POST",
    headers,
    body: JSON.stringify({
      amountLyd: 25.5,
      bankName: "مصرف الجمهورية (Demo)",
      reference: marker,
      instantDemo: true,
    }),
  });
  const topupBody: any = await topup.json().catch(() => null);
  check("topup_instant", topup.status === 201, `status=${topup.status}`);

  const getAfterTopup = await fetch(`${base}/api/wallet`, { headers });
  const afterTopup: any = await getAfterTopup.json().catch(() => null);
  check(
    "balance_after_topup_mysql",
    afterTopup?._db === "mysql" &&
      nearly(
        Number(afterTopup?.wallet?.balanceLyd),
        Number(beforeBody?.wallet?.balanceLyd) + 25.5,
      ),
    `before=${beforeBody?.wallet?.balanceLyd} after=${afterTopup?.wallet?.balanceLyd}`,
  );

  const adjust = await fetch(`${base}/api/admin/wallet/${userId}/adjust`, {
    method: "POST",
    headers,
    body: JSON.stringify({ amountLyd: -5.5, note: `${marker}-adjust` }),
  });
  const adjustBody: any = await adjust.json().catch(() => null);
  check(
    "admin_adjust",
    adjust.status === 200 && nearly(Number(adjustBody?.balanceLyd), Number(afterTopup?.wallet?.balanceLyd) - 5.5),
    `status=${adjust.status} bal=${adjustBody?.balanceLyd}`,
  );

  const getFinal = await fetch(`${base}/api/wallet`, { headers });
  const finalBody: any = await getFinal.json().catch(() => null);
  check(
    "get_after_adjust_mysql",
    finalBody?._db === "mysql" && nearly(Number(finalBody?.wallet?.balanceLyd), Number(adjustBody?.balanceLyd)),
    `api=${finalBody?.wallet?.balanceLyd}`,
  );

  const txns = await fetch(`${base}/api/admin/wallet/transactions?userId=${encodeURIComponent(userId)}`, {
    headers,
  });
  const txnsBody: any = await txns.json().catch(() => null);
  check(
    "admin_txns_mysql",
    txns.status === 200 && txnsBody?._db === "mysql" && Array.isArray(txnsBody?.transactions),
    `status=${txns.status} _db=${txnsBody?._db} count=${txnsBody?.transactions?.length}`,
  );

  const pool = await mysql.createPool({
    host: process.env.MYSQL_HOST,
    port: Number(process.env.MYSQL_PORT),
    user: process.env.MYSQL_USER,
    password: process.env.MYSQL_PASSWORD,
    database: process.env.MYSQL_DATABASE,
  });
  const [wrows] = await pool.query(`SELECT balance_lyd FROM wallets WHERE user_id = ?`, [userId]);
  const mysqlBal = Number((wrows as any[])[0]?.balance_lyd);
  check(
    "mysql_balance_matches_api",
    nearly(mysqlBal, Number(finalBody?.wallet?.balanceLyd)),
    `mysql=${mysqlBal} api=${finalBody?.wallet?.balanceLyd}`,
  );
  const [trows] = await pool.query(
    `SELECT COUNT(*) AS n FROM wallet_txns WHERE user_id = ? AND (note LIKE ? OR note LIKE ?)`,
    [userId, `%${marker}%`, `%Demo bank top-up%`],
  );
  // Cycle wrote: TOPUP (+25.5) and ADMIN_ADJUST (-5.5). Adjust note includes marker.
  const [adjRows] = await pool.query(
    `SELECT COUNT(*) AS n FROM wallet_txns WHERE user_id = ? AND note = ?`,
    [userId, `${marker}-adjust`],
  );
  check(
    "mysql_txns_for_cycle",
    Number((adjRows as any[])[0].n) === 1 && Number((trows as any[])[0].n) >= 2,
    `adjust=${(adjRows as any[])[0].n} related=${(trows as any[])[0].n}`,
  );
  await pool.end();

  const passed = results.filter((r) => r.pass).length;
  console.log(`\nSUMMARY wallets-read: ${passed}/${results.length} pass`);
  process.exit(passed === results.length ? 0 : 1);
}

main().catch((e) => {
  console.error(e instanceof Error ? e.message : e);
  process.exit(1);
});
