import { Badge } from "@/components/Badge";
import { Button } from "@/components/Button";
import { Title } from "@/components/Title";
import { Text } from "@/components/Text";
import { ImageDisplay } from "@/components/ImageDisplay";
import { ProgressBar } from "@/components/ProgressBar";
import { RichText } from "@/components/RichText";
import { Hint } from "@/components/Hint";
import { WebEmbed } from "@/components/WebEmbed";
import { Countdown } from "@/components/Countdown";
import { RingGauge } from "@/components/RingGauge";
import { FAB } from "@/components/FAB";
import { ActionRow } from "@/components/ActionRow";
import { LinkButton } from "@/components/LinkButton";
import { TabContainer } from "@/components/TabContainer";
import { cleanLabel } from "@/components/FieldLabel";
import { formatNum } from "@/utils/format";
import { BADGE_COLORS } from "@/theme/accents";
import type { ComponentSpec, PageSpec } from "@/types/spec";
import type { TableData } from "@/hooks/useData";

interface DashboardProps {
  page: PageSpec;
  data: TableData;
}

export function Dashboard({ page, data }: DashboardProps) {
  const components = page.components || [];

  // Group consecutive metrics into a flex row
  const rendered: preact.JSX.Element[] = [];
  let metricBatch: ComponentSpec[] = [];

  function flushMetrics() {
    if (metricBatch.length === 0) return;
    rendered.push(
      <div key={`m-${rendered.length}`} class="flex flex-wrap gap-3 mb-4">
        {metricBatch.map((c, i) => <MetricCard key={i} comp={c} data={data} />)}
      </div>
    );
    metricBatch = [];
  }

  for (const comp of components) {
    if (comp.type === "metric") {
      metricBatch.push(comp);
      continue;
    }
    flushMetrics();
    rendered.push(<ComponentRenderer key={rendered.length} comp={comp} data={data} />);
  }
  flushMetrics();

  return <div>{rendered}</div>;
}

function MetricCard({ comp, data }: { comp: ComponentSpec; data: TableData }) {
  let val = comp.value as number;
  if (val === 0 && comp.source) val = (data[comp.source as string] || []).length;
  const delta = comp.delta as string | undefined;

  return (
    <div class="p-4 rounded-[var(--z-radius-card)] flex-1 min-w-[120px]" style={{ border: "var(--z-card-border)", boxShadow: "var(--z-card-shadow)", background: "var(--z-card-bg)" }}>
      <p class="font-mono text-2xl font-semibold tracking-tight">
        {formatNum(val)}
        {delta && <span class={`text-xs ml-2 ${String(delta).startsWith("-") ? "text-red-400" : "text-green-400"}`}>{delta}</span>}
      </p>
      <p class="text-[var(--z-font-sm)] mt-1.5" style={{ color: "var(--z-muted)" }}>{comp.label as string}</p>
    </div>
  );
}

function ComponentRenderer({ comp, data }: { comp: ComponentSpec; data: TableData }) {
  switch (comp.type) {
    case "title":
      return <Title text={comp.text as string} size={(comp.size as any) || "lg"} subtitle={comp.subtitle as string | undefined} emphasis={comp.emphasis as string | undefined} />;

    case "text":
      return <Text content={comp.text as string} style={(comp.style as any) || "body"} />;

    case "image":
      return <ImageDisplay src={comp.src as string} shape={(comp.shape as any) || "square"} size={(comp.size as any) || "md"} alt={(comp.alt as string) || ""} />;

    case "section":
      return <div class="font-mono text-[var(--z-font-sm)] uppercase tracking-wider mt-7 mb-3 pb-2" style={{ color: "var(--z-muted)", borderBottom: "1px solid var(--z-border)" }}>{comp.title as string}</div>;

    case "progress":
      return <div class="mb-4"><ProgressBar value={comp.value as number} max={(comp.max as number) || 100} label={comp.label as string} /></div>;

    case "chart":
      return <ChartComponent comp={comp} data={data} />;

    case "list": {
      const rows = data[comp.source as string] || (comp.data as any[]) || [];
      if (!rows.length) return <p class="text-[var(--z-font-md)] py-4" style={{ color: "var(--z-muted)", opacity: 0.5 }}>{(comp.empty as string) || "No items."}</p>;
      return (
        <div class="mb-4">
          {rows.map((row: any, i: number) => {
            const t = comp.title ? row[comp.title as string] : Object.values(row)[1] || "";
            const s = comp.subtitle ? formatNum(row[comp.subtitle as string]) : "";
            const b = comp.badge && row[comp.badge as string] ? String(row[comp.badge as string]) : "";
            return (
              <div key={i} class="flex items-center justify-between rounded-[var(--z-radius-card)] mb-1 transition-colors" style={{ border: "var(--z-card-border)", boxShadow: "var(--z-card-shadow)", padding: "var(--z-density-padding)" }}
                onMouseOver={(e) => { (e.currentTarget as HTMLElement).style.background = "var(--z-card-bg)"; }}
                onMouseOut={(e) => { (e.currentTarget as HTMLElement).style.background = "transparent"; }}
              >
                <div>
                  <p class="text-[var(--z-font-md)]">{String(t)}</p>
                  {s && <p class="text-[var(--z-font-sm)]" style={{ color: "var(--z-muted)" }}>{s}</p>}
                </div>
                {b && <Badge text={b} />}
              </div>
            );
          })}
        </div>
      );
    }

    case "badge":
      return <Badge text={comp.text as string} color={(comp.color as any) || "default"} />;

    case "richtext":
      return <RichText content={(comp.content || comp.text) as string} />;

    case "hint":
      return <Hint text={comp.text as string} mood={(comp.mood as any) || "default"} icon={comp.icon as string | undefined} />;

    case "embed":
      return <WebEmbed url={comp.url as string} height={(comp.height as number) || 400} />;

    case "countdown":
      return <Countdown target={comp.target as string} label={comp.label as string} />;

    case "gauge":
      return <div class="mb-4"><RingGauge value={comp.value as number} max={(comp.max as number) || 100} label={comp.label as string} /></div>;

    case "fab":
      return <FAB icon={comp.icon as string} label={comp.label as string} />;

    case "action_row":
      return <ActionRow label={comp.label as string} subtitle={comp.subtitle as string} icon={comp.icon as string} />;

    case "link":
      return <div class="mb-2"><LinkButton text={comp.text as string} url={comp.url as string} /></div>;

    case "button":
      return <div class="mb-2 mr-2 inline-block"><Button label={comp.label as string} variant={(comp.variant as any) || "filled"} size={(comp.size as any) || "md"} icon={comp.icon as string | undefined} fullWidth={comp.full_width as boolean | undefined} /></div>;

    case "card": {
      const bgStyle = comp.background === "accent" ? { background: "var(--z-accent-dim)", border: "1px solid var(--z-accent-border)" }
        : comp.background === "dark" ? { background: "rgba(0,0,0,0.3)", border: "var(--z-card-border)" }
        : comp.background === "highlight" ? { background: "var(--z-accent-dim)", border: "none" }
        : { background: "var(--z-card-bg)", border: "var(--z-card-border)", boxShadow: "var(--z-card-shadow)" };
      return (
        <div class="rounded-[var(--z-radius-card)] overflow-hidden mb-3" style={bgStyle}>
          {comp.image && <img src={comp.image as string} alt="" class="w-full h-40 object-cover" />}
          <div class="p-4">
            <h3 class="text-sm font-semibold mb-1">{comp.title as string}</h3>
            {comp.body && <p class="text-[var(--z-font-md)] leading-relaxed" style={{ color: "var(--z-muted)" }}>{comp.body as string}</p>}
          </div>
        </div>
      );
    }

    default:
      return <div class="font-mono text-[var(--z-font-xs)] py-1" style={{ color: "var(--z-muted)", opacity: 0.3 }}>[{comp.type}]</div>;
  }
}

function ChartComponent({ comp, data }: { comp: ComponentSpec; data: TableData }) {
  const rows = data[comp.source as string] || [];
  if (!rows.length) return <div class="p-6 rounded-[var(--z-radius-card)] text-center mb-4" style={{ border: "1px dashed var(--z-border)" }}><p class="text-[var(--z-font-md)]" style={{ color: "var(--z-muted)", opacity: 0.5 }}>No data for chart</p></div>;

  const groups: Record<string, number> = {};
  for (const row of rows) {
    const key = String((row as any)[comp.x as string] || "other");
    if (!groups[key]) groups[key] = 0;
    if (comp.aggregate === "count") groups[key]++;
    else groups[key] += parseFloat(String((row as any)[comp.y as string] || 0));
  }
  const entries = Object.entries(groups);
  const total = entries.reduce((s, [, v]) => s + v, 0);
  const kind = (comp.kind as string) || "bar";

  // Pie / donut chart
  if (kind === "pie" || kind === "donut") {
    const r = 50, cx = 60, cy = 60;
    let angle = 0;
    const COLORS = ["#4ade80","#60a5fa","#a855f7","#facc15","#fb923c","#f87171","#22d3ee","#f472b6","#818cf8"];
    const slices = entries.map(([k, v], i) => {
      const pct = v / (total || 1);
      const start = angle;
      angle += pct * 360;
      const large = pct > 0.5 ? 1 : 0;
      const rad = (d: number) => (d * Math.PI) / 180;
      const x1 = cx + r * Math.cos(rad(start - 90)), y1 = cy + r * Math.sin(rad(start - 90));
      const x2 = cx + r * Math.cos(rad(start + pct * 360 - 90)), y2 = cy + r * Math.sin(rad(start + pct * 360 - 90));
      return { k, v, color: COLORS[i % COLORS.length], d: `M${cx},${cy} L${x1},${y1} A${r},${r} 0 ${large} 1 ${x2},${y2} Z` };
    });

    return (
      <div class="p-5 rounded-[var(--z-radius-card)] mb-4" style={{ border: "var(--z-card-border)", boxShadow: "var(--z-card-shadow)", background: "var(--z-card-bg)" }}>
        <span class="font-mono text-[var(--z-font-sm)]" style={{ color: "var(--z-muted)" }}>{cleanLabel(comp.y as string)} by {cleanLabel(comp.x as string)}</span>
        <div class="flex items-center gap-6 mt-3">
          <svg viewBox="0 0 120 120" width="120" height="120">
            {slices.map((s) => <path key={s.k} d={s.d} fill={s.color} />)}
            {kind === "donut" && <circle cx={cx} cy={cy} r={r * 0.55} fill="var(--z-bg)" />}
          </svg>
          <div class="space-y-1">
            {slices.map((s) => (
              <div key={s.k} class="flex items-center gap-2 text-xs">
                <span class="w-2 h-2 rounded-full shrink-0" style={{ background: s.color }} />
                <span style={{ opacity: 0.7 }}>{s.k}</span>
                <span class="font-mono" style={{ opacity: 0.4 }}>{formatNum(s.v)}</span>
              </div>
            ))}
          </div>
        </div>
      </div>
    );
  }

  // Line / area chart
  if (kind === "line" || kind === "area") {
    const max = Math.max(...entries.map(([, v]) => v), 1);
    const w = 400, h = 120, pad = 20;
    const points = entries.map(([, v], i) => {
      const x = pad + (i / Math.max(entries.length - 1, 1)) * (w - 2 * pad);
      const y = h - pad - ((v / max) * (h - 2 * pad));
      return `${x},${y}`;
    });
    const pathD = points.map((p, i) => `${i === 0 ? "M" : "L"}${p}`).join(" ");
    const areaD = `${pathD} L${pad + (w - 2 * pad)},${h - pad} L${pad},${h - pad} Z`;

    return (
      <div class="p-5 rounded-[var(--z-radius-card)] mb-4" style={{ border: "var(--z-card-border)", boxShadow: "var(--z-card-shadow)", background: "var(--z-card-bg)" }}>
        <div class="flex justify-between mb-3">
          <span class="font-mono text-[var(--z-font-sm)]" style={{ color: "var(--z-muted)" }}>{cleanLabel(comp.y as string)} by {cleanLabel(comp.x as string)}</span>
          <span class="font-mono text-[var(--z-font-sm)]" style={{ color: "var(--z-muted)", opacity: 0.5 }}>{formatNum(total)} total</span>
        </div>
        <svg viewBox={`0 0 ${w} ${h}`} class="w-full" style={{ height: "120px" }}>
          {kind === "area" && <path d={areaD} fill="var(--z-accent)" opacity="0.15" />}
          <path d={pathD} fill="none" stroke="var(--z-accent)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
          {points.map((p, i) => {
            const [x, y] = p.split(",").map(Number);
            return <circle key={i} cx={x} cy={y} r="3" fill="var(--z-accent)" />;
          })}
          {entries.map(([k], i) => {
            const x = pad + (i / Math.max(entries.length - 1, 1)) * (w - 2 * pad);
            return <text key={k} x={x} y={h - 4} text-anchor="middle" fill="var(--z-muted)" font-size="9" font-family="monospace">{k}</text>;
          })}
        </svg>
      </div>
    );
  }

  // Default: bar chart
  const max = Math.max(...entries.map(([, v]) => v), 1);
  const sorted = [...entries].sort((a, b) => b[1] - a[1]);
  return (
    <div class="p-5 rounded-[var(--z-radius-card)] mb-4" style={{ border: "var(--z-card-border)", boxShadow: "var(--z-card-shadow)", background: "var(--z-card-bg)" }}>
      <div class="flex justify-between mb-4">
        <span class="font-mono text-[var(--z-font-sm)]" style={{ color: "var(--z-muted)" }}>{cleanLabel(comp.y as string)} by {cleanLabel(comp.x as string)}</span>
        <span class="font-mono text-[var(--z-font-sm)]" style={{ color: "var(--z-muted)", opacity: 0.5 }}>{formatNum(total)} total</span>
      </div>
      <div class="space-y-2.5">
        {sorted.map(([k, v], i) => {
          const pct = Math.round((v / max) * 100);
          const color = BADGE_COLORS[i % BADGE_COLORS.length];
          return (
            <div key={k}>
              <div class="flex justify-between text-xs mb-1">
                <span style={{ opacity: 0.7 }}>{k}</span>
                <span class="font-mono" style={{ opacity: 0.5 }}>{formatNum(v)}</span>
              </div>
              <div class="h-1.5 rounded-full overflow-hidden" style={{ background: "var(--z-card-bg)" }}>
                <div class={`h-full rounded-full badge-${color} transition-all duration-500`} style={{ width: `${pct}%`, opacity: 0.8 }} />
              </div>
            </div>
          );
        })}
      </div>
    </div>
  );
}
