import type { Metadata } from "next";
import { sql } from "drizzle-orm";
import { BarChart3, Users, Mail, ShieldCheck, UserCheck } from "lucide-react";
import { requireAdmin } from "@/lib/auth/admin-guard";
import { db } from "@/lib/db/client";
import {
  users,
  applications,
  emailLog,
  adminAudit,
} from "@/lib/db/schema";
import {
  AdminHeading,
  FormSection,
  KpiCard,
} from "@/components/admin";

export const metadata: Metadata = { title: "Analytics" };
export const dynamic = "force-dynamic";

const DAYS = 30;

type DailyPoint = { day: string; count: number };

function fillGaps(raw: DailyPoint[], days: number): DailyPoint[] {
  const map = new Map(raw.map((r) => [r.day, r.count]));
  const out: DailyPoint[] = [];
  const today = new Date();
  for (let i = days - 1; i >= 0; i -= 1) {
    const d = new Date(today);
    d.setUTCDate(d.getUTCDate() - i);
    const key = d.toISOString().slice(0, 10);
    out.push({ day: key, count: map.get(key) ?? 0 });
  }
  return out;
}

function Sparkbar({
  points,
  label,
  tone,
}: {
  points: DailyPoint[];
  label: string;
  tone: "blue" | "emerald" | "amber";
}) {
  const max = Math.max(1, ...points.map((p) => p.count));
  const barClass =
    tone === "emerald"
      ? "bg-emerald-500"
      : tone === "amber"
        ? "bg-amber-500"
        : "bg-[var(--color-blue)]";
  return (
    <div>
      <div className="mb-2 flex items-center justify-between text-[11px] font-bold uppercase tracking-wider text-[var(--color-slate)]">
        <span>{label}</span>
        <span>{`max ${max}/day`}</span>
      </div>
      <div
        className="grid gap-0.5"
        style={{ gridTemplateColumns: `repeat(${points.length}, minmax(0,1fr))` }}
        role="img"
        aria-label={`${label} — last ${points.length} days`}
      >
        {points.map((p) => {
          const pct = Math.max(4, Math.round((p.count / max) * 100));
          return (
            <div
              key={p.day}
              className="flex h-20 flex-col justify-end"
              title={`${p.day}: ${p.count}`}
            >
              <div
                className={`${barClass} rounded-sm transition-all`}
                style={{ height: `${pct}%` }}
                aria-hidden
              />
            </div>
          );
        })}
      </div>
      <div className="mt-1 flex items-center justify-between text-[10px] text-[var(--color-slate)]">
        <span>{points[0]?.day}</span>
        <span>{points[points.length - 1]?.day}</span>
      </div>
    </div>
  );
}

export default async function AdminAnalyticsPage() {
  await requireAdmin();

  const [signupsRaw, approvalsRaw, emailsRaw, auditRaw, totals] =
    await Promise.all([
      db
        .select({
          day: sql<string>`to_char(${users.createdAt} at time zone 'utc', 'YYYY-MM-DD')`,
          count: sql<number>`count(*)`.mapWith(Number),
        })
        .from(users)
        .where(sql`${users.createdAt} > now() - interval '${sql.raw(String(DAYS))} days'`)
        .groupBy(sql`to_char(${users.createdAt} at time zone 'utc', 'YYYY-MM-DD')`),
      db
        .select({
          day: sql<string>`to_char(${applications.reviewedAt} at time zone 'utc', 'YYYY-MM-DD')`,
          count: sql<number>`count(*)`.mapWith(Number),
        })
        .from(applications)
        .where(
          sql`${applications.reviewedAt} is not null and ${applications.reviewedAt} > now() - interval '${sql.raw(String(DAYS))} days' and ${applications.status} = 'approved'`,
        )
        .groupBy(sql`to_char(${applications.reviewedAt} at time zone 'utc', 'YYYY-MM-DD')`),
      db
        .select({
          day: sql<string>`to_char(${emailLog.createdAt} at time zone 'utc', 'YYYY-MM-DD')`,
          count: sql<number>`count(*)`.mapWith(Number),
        })
        .from(emailLog)
        .where(sql`${emailLog.createdAt} > now() - interval '${sql.raw(String(DAYS))} days'`)
        .groupBy(sql`to_char(${emailLog.createdAt} at time zone 'utc', 'YYYY-MM-DD')`),
      db
        .select({
          day: sql<string>`to_char(${adminAudit.createdAt} at time zone 'utc', 'YYYY-MM-DD')`,
          count: sql<number>`count(*)`.mapWith(Number),
        })
        .from(adminAudit)
        .where(sql`${adminAudit.createdAt} > now() - interval '${sql.raw(String(DAYS))} days'`)
        .groupBy(sql`to_char(${adminAudit.createdAt} at time zone 'utc', 'YYYY-MM-DD')`),
      Promise.all([
        db
          .select({ n: sql<number>`count(*)`.mapWith(Number) })
          .from(users)
          .where(sql`${users.createdAt} > now() - interval '30 days'`)
          .then((r) => r[0]?.n ?? 0),
        db
          .select({ n: sql<number>`count(*)`.mapWith(Number) })
          .from(applications)
          .where(
            sql`${applications.status} = 'approved' and ${applications.reviewedAt} > now() - interval '30 days'`,
          )
          .then((r) => r[0]?.n ?? 0),
        db
          .select({ n: sql<number>`count(*)`.mapWith(Number) })
          .from(emailLog)
          .where(sql`${emailLog.createdAt} > now() - interval '30 days'`)
          .then((r) => r[0]?.n ?? 0),
        db
          .select({ n: sql<number>`count(*)`.mapWith(Number) })
          .from(adminAudit)
          .where(sql`${adminAudit.createdAt} > now() - interval '30 days'`)
          .then((r) => r[0]?.n ?? 0),
      ]),
    ]);

  const signups = fillGaps(signupsRaw as DailyPoint[], DAYS);
  const approvals = fillGaps(approvalsRaw as DailyPoint[], DAYS);
  const emails = fillGaps(emailsRaw as DailyPoint[], DAYS);
  const actions = fillGaps(auditRaw as DailyPoint[], DAYS);
  const [sumSignups, sumApprovals, sumEmails, sumActions] = totals;

  return (
    <>
      <AdminHeading
        eyebrow="Overview"
        title="Analytics"
        lede={`Activity across the last ${DAYS} days. Every metric is computed live from the database — refresh the page for fresh numbers.`}
      />

      <div className="mb-6 grid grid-cols-2 gap-4 lg:grid-cols-4">
        <KpiCard
          label="New signups (30d)"
          value={sumSignups}
          tone="blue"
          Icon={Users}
        />
        <KpiCard
          label="Approvals (30d)"
          value={sumApprovals}
          tone="emerald"
          Icon={UserCheck}
        />
        <KpiCard
          label="Emails sent (30d)"
          value={sumEmails}
          tone="ink"
          Icon={Mail}
        />
        <KpiCard
          label="Admin actions (30d)"
          value={sumActions}
          tone="slate"
          Icon={ShieldCheck}
        />
      </div>

      <div className="grid gap-4 md:grid-cols-2">
        <FormSection
          title="Daily signups"
          description="New rows in the users table, regardless of application status."
        >
          <Sparkbar points={signups} label="Signups per day" tone="blue" />
        </FormSection>
        <FormSection
          title="Daily approvals"
          description="Applications transitioning to approved — excludes self-registered admins."
        >
          <Sparkbar
            points={approvals}
            label="Approvals per day"
            tone="emerald"
          />
        </FormSection>
        <FormSection
          title="Email volume"
          description="Every outbound transactional email — sent, failed, and dev-console."
        >
          <Sparkbar points={emails} label="Emails per day" tone="amber" />
        </FormSection>
        <FormSection
          title="Admin actions"
          description="Every audit-logged admin action. Useful for spotting bursts of activity."
        >
          <Sparkbar points={actions} label="Admin actions per day" tone="blue" />
        </FormSection>
      </div>

      <div className="mt-8 flex items-start gap-2 rounded-md border border-blue-200 bg-blue-50 p-3 text-[12px] text-blue-900">
        <BarChart3 className="mt-0.5 h-4 w-4 shrink-0" aria-hidden />
        <span>
          These are server-side metrics only — no client tracking, no
          third-party analytics. If you want page-view telemetry, wire
          Plausible or Umami at the app layer.
        </span>
      </div>
    </>
  );
}
