import { eq, and, gte, lte, desc } from "drizzle-orm";
import { kpiSnapshots } from "../../db/schema";
import type { DrizzleDB } from "../../db/config/migrations";
import type { NewKPISnapshot, KPISnapshot } from "../../db/schema";

export type KPIKey =
  | "mau"
  | "paying_users"
  | "mrr"
  | "conversion_rate"
  | "churn_rate"
  | "cac"
  | "ltv"
  | "nps"
  | "viral_coefficient";

export const KPI_THRESHOLDS: Record<KPIKey, { warning: number; critical: number; direction: "higher" | "lower" }> = {
  mau: { warning: 1000, critical: 500, direction: "higher" },
  paying_users: { warning: 100, critical: 50, direction: "higher" },
  mrr: { warning: 5000, critical: 2000, direction: "higher" },
  conversion_rate: { warning: 2, critical: 1, direction: "higher" },
  churn_rate: { warning: 5, critical: 3, direction: "lower" },
  cac: { warning: 12, critical: 15, direction: "lower" },
  ltv: { warning: 100, critical: 80, direction: "higher" },
  nps: { warning: 40, critical: 20, direction: "higher" },
  viral_coefficient: { warning: 0.3, critical: 0.1, direction: "higher" },
};

export async function recordKPI(
  db: DrizzleDB,
  kpiKey: KPIKey,
  value: number,
  periodStart: Date,
  periodEnd: Date,
  metadata?: Record<string, unknown>
): Promise<KPISnapshot> {
  const snapshot: NewKPISnapshot = {
    kpiKey,
    kpiValue: value,
    periodStart,
    periodEnd,
    metadata: metadata ? JSON.stringify(metadata) : null,
  };
  const result = await db.insert(kpiSnapshots).values(snapshot).returning();
  return result[0]!;
}

export async function getLatestKPI(
  db: DrizzleDB,
  kpiKey: KPIKey
): Promise<KPISnapshot | undefined> {
  const rows = await db
    .select()
    .from(kpiSnapshots)
    .where(eq(kpiSnapshots.kpiKey, kpiKey))
    .orderBy(desc(kpiSnapshots.createdAt))
    .limit(1);
  return rows[0];
}

export async function getKPIHistory(
  db: DrizzleDB,
  kpiKey: KPIKey,
  periodStart?: Date,
  periodEnd?: Date
): Promise<KPISnapshot[]> {
  const conditions: import("drizzle-orm").SQL[] = [eq(kpiSnapshots.kpiKey, kpiKey)];

  if (periodStart) {
    conditions.push(gte(kpiSnapshots.periodStart, periodStart));
  }
  if (periodEnd) {
    conditions.push(lte(kpiSnapshots.periodEnd, periodEnd));
  }

  return await db
    .select()
    .from(kpiSnapshots)
    .where(and(...conditions))
    .orderBy(kpiSnapshots.periodStart);
}

export async function getAllLatestKPIs(db: DrizzleDB): Promise<Record<KPIKey, KPISnapshot | undefined>> {
  const result: Record<KPIKey, KPISnapshot | undefined> = {} as Record<KPIKey, KPISnapshot | undefined>;
  const keys = Object.keys(KPI_THRESHOLDS) as KPIKey[];

  for (const key of keys) {
    result[key] = await getLatestKPI(db, key);
  }

  return result;
}

export function checkKPIAgainstThreshold(
  kpiKey: KPIKey,
  value: number
): { breached: boolean; severity: "warning" | "critical" | null } {
  const thresholds = KPI_THRESHOLDS[kpiKey];
  if (!thresholds) return { breached: false, severity: null };

  const { warning, critical, direction } = thresholds;
  const isHigher = direction === "higher";

  if (isHigher) {
    if (value <= critical) return { breached: true, severity: "critical" };
    if (value <= warning) return { breached: true, severity: "warning" };
  } else {
    if (value >= critical) return { breached: true, severity: "critical" };
    if (value >= warning) return { breached: true, severity: "warning" };
  }

  return { breached: false, severity: null };
}

export function getKPIStatus(
  kpiKey: KPIKey,
  value: number
): "healthy" | "warning" | "critical" {
  const { breached, severity } = checkKPIAgainstThreshold(kpiKey, value);
  if (!breached) return "healthy";
  return severity === "critical" ? "critical" : "warning";
}
