import { createServerFn } from "@tanstack/react-start";
import { z } from "zod";
import { requireSupabaseAuth } from "@/integrations/supabase/auth-middleware";

export interface LeadRow {
  id: string;
  name: string;
  email: string;
  company: string | null;
  message: string;
  source: string;
  status: "new" | "contacted" | "qualified" | "archived";
  internal_notes: string | null;
  created_at: string;
}

async function assertAdmin(context: { supabase: any; userId: string }) {
  const { data, error } = await context.supabase.rpc("has_role", {
    _user_id: context.userId,
    _role: "admin",
  });
  if (error) throw new Error("Could not verify your permissions.");
  if (!data) throw new Error("Forbidden: admin access required.");
}

export const isAdmin = createServerFn({ method: "GET" })
  .middleware([requireSupabaseAuth])
  .handler(async ({ context }) => {
    const { data } = await context.supabase.rpc("has_role", {
      _user_id: context.userId,
      _role: "admin",
    });
    return { isAdmin: Boolean(data), email: context.claims?.email ?? null };
  });

export const listLeads = createServerFn({ method: "GET" })
  .middleware([requireSupabaseAuth])
  .handler(async ({ context }) => {
    await assertAdmin(context);
    const { data, error } = await context.supabase
      .from("contact_submissions")
      .select("*")
      .order("created_at", { ascending: false });
    if (error) throw new Error(error.message);
    return (data ?? []) as LeadRow[];
  });

export const updateLead = createServerFn({ method: "POST" })
  .middleware([requireSupabaseAuth])
  .inputValidator((input: { id: string; status?: string; internal_notes?: string }) =>
    z
      .object({
        id: z.string().uuid(),
        status: z.enum(["new", "contacted", "qualified", "archived"]).optional(),
        internal_notes: z.string().max(4000).optional(),
      })
      .parse(input),
  )
  .handler(async ({ data, context }) => {
    await assertAdmin(context);
    const patch: { status?: LeadRow["status"]; internal_notes?: string } = {};
    if (data.status) patch.status = data.status;
    if (data.internal_notes !== undefined) patch.internal_notes = data.internal_notes;
    const { error } = await context.supabase
      .from("contact_submissions")
      .update(patch)
      .eq("id", data.id);
    if (error) throw new Error(error.message);
    return { ok: true as const };
  });

export const deleteLead = createServerFn({ method: "POST" })
  .middleware([requireSupabaseAuth])
  .inputValidator((input: { id: string }) => z.object({ id: z.string().uuid() }).parse(input))
  .handler(async ({ data, context }) => {
    await assertAdmin(context);
    const { error } = await context.supabase
      .from("contact_submissions")
      .delete()
      .eq("id", data.id);
    if (error) throw new Error(error.message);
    return { ok: true as const };
  });

export interface AnalyticsBucket {
  label: string;
  accepted: number;
  rejected: number;
  failed: number;
}

export interface LeadAnalytics {
  windowDays: number;
  totals: { accepted: number; rejected: number; failed: number; all: number };
  acceptanceRate: number;
  reasons: { reason: string; count: number }[];
  sources: { source: string; count: number }[];
  buckets: AnalyticsBucket[];
  recent: { created_at: string; outcome: string; reason: string | null; email: string | null }[];
}

export const leadAnalytics = createServerFn({ method: "POST" })
  .middleware([requireSupabaseAuth])
  .inputValidator((input: { windowDays?: number }) =>
    z.object({ windowDays: z.number().int().min(1).max(365).default(30) }).parse(input ?? {}),
  )
  .handler(async ({ data, context }): Promise<LeadAnalytics> => {
    await assertAdmin(context);
    const since = new Date(Date.now() - data.windowDays * 86_400_000);

    const [eventsRes, leadsRes] = await Promise.all([
      context.supabase
        .from("contact_submission_events")
        .select("created_at, outcome, reason, email")
        .gte("created_at", since.toISOString())
        .order("created_at", { ascending: false }),
      context.supabase
        .from("contact_submissions")
        .select("created_at, source")
        .gte("created_at", since.toISOString()),
    ]);

    if (eventsRes.error) throw new Error(eventsRes.error.message);
    if (leadsRes.error) throw new Error(leadsRes.error.message);

    const events = (eventsRes.data ?? []) as {
      created_at: string;
      outcome: string;
      reason: string | null;
      email: string | null;
    }[];

    const totals = { accepted: 0, rejected: 0, failed: 0, all: events.length };
    const reasonCounts = new Map<string, number>();
    const bucketMap = new Map<string, AnalyticsBucket>();

    const dayKey = (iso: string) => new Date(iso).toISOString().slice(0, 10);
    for (let i = data.windowDays - 1; i >= 0; i--) {
      const key = new Date(Date.now() - i * 86_400_000).toISOString().slice(0, 10);
      bucketMap.set(key, { label: key, accepted: 0, rejected: 0, failed: 0 });
    }

    for (const event of events) {
      const outcome = event.outcome === "accepted" ? "accepted" : event.outcome === "failed" ? "failed" : "rejected";
      totals[outcome] += 1;
      if (outcome !== "accepted" && event.reason) {
        reasonCounts.set(event.reason, (reasonCounts.get(event.reason) ?? 0) + 1);
      }
      const bucket = bucketMap.get(dayKey(event.created_at));
      if (bucket) bucket[outcome] += 1;
    }

    const sourceCounts = new Map<string, number>();
    for (const lead of (leadsRes.data ?? []) as { source: string }[]) {
      sourceCounts.set(lead.source, (sourceCounts.get(lead.source) ?? 0) + 1);
    }

    return {
      windowDays: data.windowDays,
      totals,
      acceptanceRate: totals.all ? Math.round((totals.accepted / totals.all) * 100) : 0,
      reasons: [...reasonCounts.entries()]
        .map(([reason, count]) => ({ reason, count }))
        .sort((a, b) => b.count - a.count),
      sources: [...sourceCounts.entries()]
        .map(([source, count]) => ({ source, count }))
        .sort((a, b) => b.count - a.count),
      buckets: [...bucketMap.values()],
      recent: events.slice(0, 25),
    };
  });

