import { db, jobs, invoices } from "@workspace/db";
import { sql } from "drizzle-orm";
import { latencyHistogram, type BucketStats } from "./histogram.js";

export interface JobStateCounts {
  awaiting_eval: number;
  awaiting_work: number;
  complete: number;
  rejected: number;
  failed: number;
}

export interface MetricsSnapshot {
  uptime_s: number;
  jobs: {
    total: number;
    by_state: JobStateCounts;
  };
  invoices: {
    total: number;
    paid: number;
    conversion_rate: number | null;
  };
  earnings: {
    total_sats: number;
  };
  latency: {
    eval_phase: BucketStats | null;
    work_phase: BucketStats | null;
    routes: Record<string, BucketStats>;
  };
}

const START_TIME = Date.now();

export class MetricsService {
  async snapshot(): Promise<MetricsSnapshot> {
    const [jobsByState, invoiceCounts, earningsRow] = await Promise.all([
      db
        .select({
          state: jobs.state,
          count: sql<number>`cast(count(*) as int)`,
        })
        .from(jobs)
        .groupBy(jobs.state),

      db
        .select({
          total: sql<number>`cast(count(*) as int)`,
          paid:  sql<number>`cast(sum(case when paid then 1 else 0 end) as int)`,
        })
        .from(invoices),

      db
        .select({
          total_sats: sql<number>`cast(coalesce(sum(actual_amount_sats), 0) as int)`,
        })
        .from(jobs),
    ]);

    // Group raw DB states into operational state keys
    const rawCounts: Record<string, number> = {};
    let jobsTotal = 0;
    for (const row of jobsByState) {
      const n = Number(row.count);
      rawCounts[row.state] = (rawCounts[row.state] ?? 0) + n;
      jobsTotal += n;
    }

    const byState: JobStateCounts = {
      awaiting_eval: (rawCounts["awaiting_eval_payment"] ?? 0) + (rawCounts["evaluating"] ?? 0),
      awaiting_work: (rawCounts["awaiting_work_payment"] ?? 0) + (rawCounts["executing"] ?? 0),
      complete:  rawCounts["complete"] ?? 0,
      rejected:  rawCounts["rejected"] ?? 0,
      failed:    rawCounts["failed"] ?? 0,
    };

    const invRow = invoiceCounts[0] ?? { total: 0, paid: 0 };
    const invTotal = Number(invRow.total);
    const invPaid  = Number(invRow.paid);
    const conversionRate = invTotal > 0 ? invPaid / invTotal : null;

    const totalSats = Number(earningsRow[0]?.total_sats ?? 0);

    const allRoutes = latencyHistogram.snapshot();
    const evalPhase = allRoutes["eval_phase"] ?? null;
    const workPhase = allRoutes["work_phase"] ?? null;
    const routeLatency: Record<string, BucketStats> = {};
    for (const [key, stats] of Object.entries(allRoutes)) {
      if (key !== "eval_phase" && key !== "work_phase") {
        routeLatency[key] = stats;
      }
    }

    return {
      uptime_s: Math.floor((Date.now() - START_TIME) / 1000),
      jobs: {
        total: jobsTotal,
        by_state: byState,
      },
      invoices: {
        total: invTotal,
        paid: invPaid,
        conversion_rate: conversionRate,
      },
      earnings: {
        total_sats: totalSats,
      },
      latency: {
        eval_phase: evalPhase,
        work_phase: workPhase,
        routes: routeLatency,
      },
    };
  }
}

export const metricsService = new MetricsService();
