import { useEffect, useMemo, useState } from "react";
import { toast } from "sonner";
import { useServerFn } from "@tanstack/react-start";
import { getFormMetrics } from "@/lib/forms.functions";
import { handleAuthErrorOrThrow, isAuthError } from "@/lib/handle-auth-error";


type Agg = { views: number; starts: number; submissions: number };
type Metrics = {
  bySlug: (Agg & { slug: string; name: string })[];
  byDate: (Agg & { date: string })[];
  byCampaign: (Agg & { utm_source: string; utm_medium: string; utm_campaign: string })[];
  bySlugDate: (Agg & { slug: string; date: string })[];
};

function conv(a: Agg) {
  return a.views ? Math.round((a.submissions / a.views) * 1000) / 10 : 0;
}

function toISO(d: string, end = false) {
  if (!d) return undefined;
  return new Date(`${d}T${end ? "23:59:59.999" : "00:00:00.000"}Z`).toISOString();
}

function defaultRange() {
  const end = new Date();
  const start = new Date();
  start.setDate(end.getDate() - 29);
  const fmt = (d: Date) => d.toISOString().slice(0, 10);
  return { start: fmt(start), end: fmt(end) };
}

export function FormMetricsPanel() {
  const fetchMetrics = useServerFn(getFormMetrics);
  const [range, setRange] = useState(defaultRange());
  const [loading, setLoading] = useState(true);
  const [data, setData] = useState<Metrics | null>(null);
  const [slugFilter, setSlugFilter] = useState<string>("");

  const load = async () => {
    setLoading(true);
    try {
      const r = (await fetchMetrics({
        data: { start: toISO(range.start), end: toISO(range.end, true) },
      })) as Metrics;
      setData(r);
    } catch (e) {
      if (isAuthError(e)) {
        await handleAuthErrorOrThrow(e);
        return;
      }
      toast.error(e instanceof Error ? e.message : "Erro ao carregar métricas");
    } finally {
      setLoading(false);
    }
  };


  useEffect(() => {
    void load();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [range.start, range.end]);

  const filteredByDate = useMemo(() => {
    if (!data) return [];
    if (!slugFilter) return data.byDate;
    const rows = data.bySlugDate.filter((r) => r.slug === slugFilter);
    const map = new Map<string, Agg>();
    for (const r of rows) {
      const cur = map.get(r.date) ?? { views: 0, starts: 0, submissions: 0 };
      cur.views += r.views;
      cur.starts += r.starts;
      cur.submissions += r.submissions;
      map.set(r.date, cur);
    }
    return Array.from(map.entries())
      .map(([date, v]) => ({ date, ...v }))
      .sort((a, b) => (a.date < b.date ? 1 : -1));
  }, [data, slugFilter]);

  const totals = useMemo<Agg>(() => {
    const src = slugFilter
      ? (data?.bySlug.filter((s) => s.slug === slugFilter) ?? [])
      : (data?.bySlug ?? []);
    return src.reduce(
      (acc, r) => ({
        views: acc.views + r.views,
        starts: acc.starts + r.starts,
        submissions: acc.submissions + r.submissions,
      }),
      { views: 0, starts: 0, submissions: 0 },
    );
  }, [data, slugFilter]);

  const exportCsv = () => {
    if (!data) return;
    const lines = ["scope,key,views,starts,submissions,conversion"];
    for (const r of data.bySlug)
      lines.push(`form,${r.slug},${r.views},${r.starts},${r.submissions},${conv(r)}%`);
    for (const r of filteredByDate)
      lines.push(`date,${r.date},${r.views},${r.starts},${r.submissions},${conv(r)}%`);
    for (const r of data.byCampaign)
      lines.push(
        `campaign,"${r.utm_source} / ${r.utm_medium} / ${r.utm_campaign}",${r.views},${r.starts},${r.submissions},${conv(r)}%`,
      );
    const blob = new Blob([lines.join("\n")], { type: "text/csv" });
    const url = URL.createObjectURL(blob);
    const a = document.createElement("a");
    a.href = url;
    a.download = `form-metrics-${range.start}_${range.end}.csv`;
    a.click();
    URL.revokeObjectURL(url);
  };

  return (
    <div className="rounded-2xl border border-border bg-card p-5 space-y-5">
      <div className="flex flex-wrap items-end gap-3 justify-between">
        <div>
          <h3 className="text-sm font-black uppercase tracking-wider">
            Métricas dos formulários
          </h3>
          <p className="text-xs text-muted-foreground">
            Views, inícios, envios e taxa de conversão por formulário, data e campanha/UTM.
          </p>
        </div>
        <div className="flex flex-wrap items-end gap-2">
          <label className="text-xs text-muted-foreground flex flex-col">
            De
            <input
              type="date"
              value={range.start}
              onChange={(e) => setRange((r) => ({ ...r, start: e.target.value }))}
              className="rounded-lg border border-border bg-background px-2 py-1.5 text-sm"
            />
          </label>
          <label className="text-xs text-muted-foreground flex flex-col">
            Até
            <input
              type="date"
              value={range.end}
              onChange={(e) => setRange((r) => ({ ...r, end: e.target.value }))}
              className="rounded-lg border border-border bg-background px-2 py-1.5 text-sm"
            />
          </label>
          <label className="text-xs text-muted-foreground flex flex-col">
            Formulário
            <select
              value={slugFilter}
              onChange={(e) => setSlugFilter(e.target.value)}
              className="rounded-lg border border-border bg-background px-2 py-1.5 text-sm"
            >
              <option value="">Todos</option>
              {(data?.bySlug ?? []).map((f) => (
                <option key={f.slug} value={f.slug}>
                  {f.name} (/{f.slug})
                </option>
              ))}
            </select>
          </label>
          <button
            onClick={exportCsv}
            className="rounded-lg border border-border px-3 py-2 text-xs font-semibold hover:bg-muted"
          >
            Exportar CSV
          </button>
        </div>
      </div>

      <div className="grid grid-cols-2 md:grid-cols-4 gap-3">
        <MetricCard label="Views" value={totals.views} />
        <MetricCard label="Inícios" value={totals.starts} />
        <MetricCard label="Envios" value={totals.submissions} />
        <MetricCard label="Conversão" value={`${conv(totals)}%`} />
      </div>

      {loading ? (
        <div className="text-sm text-muted-foreground">Carregando…</div>
      ) : (
        <>
          <MetricsTable
            title="Por formulário"
            headers={["Formulário", "Views", "Inícios", "Envios", "Conv."]}
            rows={(data?.bySlug ?? [])
              .filter((r) => !slugFilter || r.slug === slugFilter)
              .sort((a, b) => b.submissions - a.submissions || b.views - a.views)
              .map((r) => [
                <span key="n">
                  <span className="font-semibold">{r.name}</span>
                  <span className="ml-2 text-xs font-mono text-muted-foreground">/f/{r.slug}</span>
                </span>,
                r.views,
                r.starts,
                r.submissions,
                `${conv(r)}%`,
              ])}
          />

          <MetricsTable
            title="Por data"
            headers={["Data", "Views", "Inícios", "Envios", "Conv."]}
            rows={filteredByDate.map((r) => [r.date, r.views, r.starts, r.submissions, `${conv(r)}%`])}
          />

          <MetricsTable
            title="Por campanha / UTM"
            headers={["Source", "Medium", "Campaign", "Views", "Inícios", "Envios", "Conv."]}
            rows={(data?.byCampaign ?? []).map((r) => [
              r.utm_source,
              r.utm_medium,
              r.utm_campaign,
              r.views,
              r.starts,
              r.submissions,
              `${conv(r)}%`,
            ])}
          />
        </>
      )}
    </div>
  );
}

function MetricCard({ label, value }: { label: string; value: number | string }) {
  return (
    <div className="rounded-xl border border-border bg-background p-4">
      <div className="text-xs uppercase tracking-wider text-muted-foreground">{label}</div>
      <div className="mt-1 text-2xl font-black font-mono">{value}</div>
    </div>
  );
}

function MetricsTable({
  title,
  headers,
  rows,
}: {
  title: string;
  headers: string[];
  rows: (string | number | React.ReactNode)[][];
}) {
  return (
    <div>
      <h4 className="mb-2 text-xs font-black uppercase tracking-wider text-muted-foreground">
        {title}
      </h4>
      <div className="overflow-x-auto rounded-xl border border-border">
        <table className="w-full text-sm">
          <thead className="bg-muted/40 text-left text-xs uppercase tracking-wider text-muted-foreground">
            <tr>
              {headers.map((h, i) => (
                <th
                  key={h}
                  className={`px-3 py-2 ${i === 0 ? "" : "text-center"}`}
                >
                  {h}
                </th>
              ))}
            </tr>
          </thead>
          <tbody>
            {rows.length === 0 ? (
              <tr>
                <td colSpan={headers.length} className="px-3 py-6 text-center text-muted-foreground">
                  Sem dados no período.
                </td>
              </tr>
            ) : (
              rows.map((r, idx) => (
                <tr key={idx} className="border-t border-border hover:bg-muted/20">
                  {r.map((cell, i) => (
                    <td
                      key={i}
                      className={`px-3 py-2 ${i === 0 ? "" : "text-center font-mono"}`}
                    >
                      {cell}
                    </td>
                  ))}
                </tr>
              ))
            )}
          </tbody>
        </table>
      </div>
    </div>
  );
}
