import { existsSync } from "node:fs";
import { join } from "node:path";
import { summary, getSessionGain } from "../../stats/reporter.ts";
import { renderGainSummary as renderGainFull } from "../../stats/format.ts";
import { renderGainSummary } from "../../stats/renderGain.ts";
import { paths } from "../../lifecycle/paths.ts";
import { Database } from "bun:sqlite";

const DAY_MS = 24 * 60 * 60 * 1000;

export async function cmdGain(flags: Record<string, string | true>, verbose = false): Promise<number> {
  const projectFilter = typeof flags["project-dir"] === "string" ? flags["project-dir"] : undefined;
  const statsDir = typeof flags["stats-dir"] === "string" ? flags["stats-dir"] : paths.root();
  const since = parseSince(typeof flags["since"] === "string" ? flags["since"] : undefined);
  const format = (typeof flags["format"] === "string" ? flags["format"] : "table") as "table" | "json";
  const defaultModel = typeof flags["model"] === "string" ? flags["model"] : undefined;

  if (typeof flags["session"] === "string") {
    const sessionId = flags["session"];
    if (!existsSync(join(statsDir, "stats.db"))) return 1;
    const db = new Database(join(statsDir, "stats.db"), { readonly: true });
    try {
      const g = getSessionGain(db, sessionId);
      process.stdout.write(JSON.stringify({
        tokensSaved: g.tokensSaved,
        dollarsSaved: g.dollarsSaved,
        dollarsSpent: g.dollarsSpentWithFt,
        dollarsCounterfactual: g.dollarsCounterfactual,
        requests: g.requests,
      }) + "\n");
    } finally {
      db.close();
    }
    return 0;
  }

  if (!existsSync(join(statsDir, "stats.db"))) {
    console.log(verbose ? "no stats yet — run a session through fewtok first" : "err=no-stats");
    return 0;
  }

  if (flags["by-adapter"] !== undefined) {
    const db = new Database(join(statsDir, "stats.db"), { readonly: true });
    try {
      const rows = db.query<
        { adapter_id: string | null; bytes_saved: number; events: number },
        []
      >(`
        SELECT
          json_extract(meta, '$.adapterId') AS adapter_id,
          SUM(raw_bytes - sent_bytes)       AS bytes_saved,
          COUNT(*)                          AS events
        FROM saving_events
        WHERE kind = 'adapter'
          AND json_extract(meta, '$.adapterId') IS NOT NULL
        GROUP BY adapter_id
        ORDER BY bytes_saved DESC, adapter_id ASC
      `).all();
      if (format === "json") {
        process.stdout.write(JSON.stringify(rows, null, 2) + "\n");
        return 0;
      }
      if (rows.length === 0) {
        console.log(verbose ? "no adapter events yet" : "events=0");
        return 0;
      }
      const idW = Math.max(10, ...rows.map(r => (r.adapter_id ?? "").length));
      const bW  = Math.max(11, ...rows.map(r => String(r.bytes_saved ?? 0).length));
      process.stdout.write(`${"adapter_id".padEnd(idW)}  ${"bytes_saved".padStart(bW)}  events\n`);
      for (const r of rows) {
        process.stdout.write(`${(r.adapter_id ?? "").padEnd(idW)}  ${String(r.bytes_saved ?? 0).padStart(bW)}  ${r.events}\n`);
      }
    } finally {
      db.close();
    }
    return 0;
  }

  const s = summary(statsDir, { sinceMs: since, ...(projectFilter ? { project: projectFilter } : {}), ...(defaultModel ? { defaultModel } : {}) });
  if (format === "json") {
    process.stdout.write(JSON.stringify(s, null, 2) + "\n");
    return 0;
  }
  if (!verbose) {
    console.log(renderGainSummary(s.totals));
    return 0;
  }
  process.stdout.write(renderGainFull(s, { width: 78 }) + "\n");
  return 0;
}

function parseSince(s?: string): number {
  if (!s) return 0;
  if (s === "today") return Date.now() - DAY_MS;
  const m = s.match(/^(\d+)([smhd])$/);
  if (m) {
    const n = parseInt(m[1]!, 10);
    const unit = m[2] as "s" | "m" | "h" | "d";
    const mult = { s: 1000, m: 60_000, h: 3_600_000, d: 86_400_000 }[unit];
    return Date.now() - n * mult;
  }
  return Date.parse(s) || 0;
}
