import { createFileRoute, Link, useNavigate } from "@tanstack/react-router";
import { useMemo, useState } from "react";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { DashboardLayout } from "@/components/dashboard-layout";
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Textarea } from "@/components/ui/textarea";
import { Badge } from "@/components/ui/badge";
import { Checkbox } from "@/components/ui/checkbox";
import { Switch } from "@/components/ui/switch";
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";
import { Calendar } from "@/components/ui/calendar";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import { toast } from "sonner";
import { cn } from "@/lib/utils";
import { WizardStepper } from "@/components/campaigns/wizard-stepper";
import { CostEstimator } from "@/components/campaigns/cost-estimator";
import { ChannelConfig } from "@/components/campaigns/channel-config";
import {
  CAMPAIGN_TYPES,
  CHANNELS,
  type ChannelId,
  SAVED_AUDIENCES,
  MEDIA_LIBRARY,
  formatCount,
  formatNaira,
} from "@/lib/campaign-data";
import { listSegmentsFn } from "@/lib/voters/voters.functions";
import {
  saveCampaignDraftFn,
  submitCampaignForSchedulingFn,
} from "@/lib/campaigns/campaigns.functions";
import { calculateCampaignEstimate } from "@/lib/campaigns/engine";
import type { AudienceTarget, CampaignFormPayload, ScheduleCadence } from "@/lib/campaigns/types";
import {
  ArrowLeft,
  ArrowRight,
  X,
  CalendarDays,
  Clock,
  Sparkles,
  Upload,
  Check,
  Image as ImageIcon,
  Video,
  Mic,
  Rocket,
  Save,
  AlertTriangle,
} from "lucide-react";
import { format } from "date-fns";

export const Route = createFileRoute("/campaigns/new")({
  head: () => ({ meta: [{ title: "New campaign — VotersAlert" }] }),
  component: NewCampaign,
});

const STEPS = [
  { id: 1, title: "Type", description: "Campaign objective" },
  { id: 2, title: "Audience", description: "Targeting & reach" },
  { id: 3, title: "Content", description: "Per-channel creative" },
  { id: 4, title: "Media", description: "Images, video, voice" },
  { id: 5, title: "Schedule", description: "Send time & cadence" },
  { id: 6, title: "Review", description: "Approve & launch" },
];

function NewCampaign() {
  const navigate = useNavigate();
  const queryClient = useQueryClient();
  const [step, setStep] = useState(1);
  const [draftId, setDraftId] = useState<string | undefined>();
  const [name, setName] = useState("New voter outreach campaign");
  const [type, setType] = useState("mobilization");
  const [audienceId, setAudienceId] = useState("a1");
  const [channels, setChannels] = useState<ChannelId[]>(["sms", "whatsapp"]);
  const [activeChannel, setActiveChannel] = useState<ChannelId>("sms");
  const [content, setContent] = useState<Record<string, string>>({
    sms_body:
      "Dear {{first_name}}, vote for change on Feb 25. PU: {{ward}}. Reply STOP to opt out.",
  });
  const [selectedMedia, setSelectedMedia] = useState<string[]>(["m1", "m4"]);
  const [date, setDate] = useState<Date | undefined>(new Date(Date.now() + 86_400_000));
  const [sendNow, setSendNow] = useState(false);
  const [timezone, setTimezone] = useState("Africa/Lagos");
  const [sendTime, setSendTime] = useState("09:30");
  const [throttle, setThrottle] = useState("balanced");
  const [acceptedCompliance, setAcceptedCompliance] = useState(false);

  const segmentsQuery = useQuery({ queryKey: ["voters", "segments"], queryFn: () => listSegmentsFn() });
  const audienceOptions = useMemo(() => {
    const savedSegments = (segmentsQuery.data ?? []).map((segment) => ({
      id: segment.id,
      name: segment.name,
      size: segment.cachedCount ?? 0,
      description: `${segment.filters.states.join(", ") || "All states"} · ${segment.channels.length || "all"} channel(s)`,
      filters: segment.filters,
    }));
    return savedSegments.length ? savedSegments : SAVED_AUDIENCES;
  }, [segmentsQuery.data]);

  const audience = audienceOptions.find((a) => a.id === audienceId) ?? audienceOptions[0];
  const audienceSize = audience.size;
  const estimate = useMemo(
    () => calculateCampaignEstimate(channels, audienceSize, {}, content),
    [channels, audienceSize, content],
  );
  const total = estimate.total;

  const toggleChannel = (id: ChannelId) => {
    setChannels((prev) => {
      const next = prev.includes(id) ? prev.filter((c) => c !== id) : [...prev, id];
      if (!next.includes(activeChannel) && next.length > 0) setActiveChannel(next[0]);
      return next;
    });
  };

  const setContentKV = (k: string, v: string) => setContent((p) => ({ ...p, [k]: v }));

  const next = () => setStep((s) => Math.min(6, s + 1));
  const prev = () => setStep((s) => Math.max(1, s - 1));

  const buildPayload = (): CampaignFormPayload => ({
    id: draftId,
    name,
    type: type as CampaignFormPayload["type"],
    step,
    audience: {
      segmentId: audience.id,
      name: audience.name,
      description: audience.description,
      size: audience.size,
      filters: "filters" in audience ? audience.filters : null,
    } as AudienceTarget,
    channels,
    channelConfig: Object.fromEntries(
      channels.map((id) => [id, { allocationPct: 1, content }]),
    ) as CampaignFormPayload["channelConfig"],
    content,
    mediaIds: selectedMedia,
    schedule: {
      sendNow,
      date: date ? format(date, "yyyy-MM-dd") : null,
      sendTime,
      timezone,
      cadence: throttle as ScheduleCadence,
    },
    complianceAccepted: acceptedCompliance,
  });

  const saveMutation = useMutation({
    mutationFn: () => saveCampaignDraftFn({ data: buildPayload() }),
    onSuccess: (saved) => {
      setDraftId(saved.id);
      toast.success("Draft saved", { description: `${saved.name} is stored for later editing.` });
      queryClient.invalidateQueries({ queryKey: ["campaigns"] });
    },
    onError: (err) => toast.error(err instanceof Error ? err.message : "Draft save failed"),
  });

  const scheduleMutation = useMutation({
    mutationFn: () => submitCampaignForSchedulingFn({ data: buildPayload() }),
    onSuccess: (saved) => {
      toast.success("Campaign scheduled", {
        description: `${saved.name} is stored as scheduled. Delivery is disabled in Stage 4.`,
      });
      queryClient.invalidateQueries({ queryKey: ["campaigns"] });
      setTimeout(() => navigate({ to: "/campaigns" }), 600);
    },
    onError: (err) => toast.error(err instanceof Error ? err.message : "Scheduling failed"),
  });

  const scheduleCampaign = () => {
    scheduleMutation.mutate();
  };

  return (
    <DashboardLayout>
      <div className="p-4 sm:p-6 lg:p-8 max-w-[1600px] mx-auto space-y-6">
        {/* Sticky header */}
        <div className="flex flex-wrap items-center justify-between gap-3">
          <div className="flex items-center gap-3">
            <Button variant="ghost" size="sm" asChild>
              <Link to="/campaigns">
                <X className="h-4 w-4" />
              </Link>
            </Button>
            <div>
              <Input
                value={name}
                onChange={(e) => setName(e.target.value)}
                className="h-8 text-base font-semibold border-transparent hover:border-input focus:border-input -ml-2 px-2 max-w-md"
              />
              <div className="text-xs text-muted-foreground ml-0">Draft · Step {step} of 6 · delivery disabled</div>
            </div>
          </div>
          <div className="flex items-center gap-2">
            <Button
              variant="outline"
              size="sm"
              className="gap-1.5"
              onClick={() => saveMutation.mutate()}
              disabled={saveMutation.isPending}
            >
              <Save className="h-3.5 w-3.5" /> Save draft
            </Button>
            {step < 6 ? (
              <Button size="sm" className="gap-1.5" onClick={next}>
                Continue <ArrowRight className="h-3.5 w-3.5" />
              </Button>
            ) : (
              <Button size="sm" className="gap-1.5" onClick={scheduleCampaign} disabled={!acceptedCompliance || scheduleMutation.isPending}>
                <Rocket className="h-3.5 w-3.5" /> Schedule campaign
              </Button>
            )}
          </div>
        </div>

        <WizardStepper steps={STEPS} current={step} onJump={setStep} />

        <div className="grid gap-6 lg:grid-cols-[1fr_320px]">
          <div className="space-y-4 min-w-0">
            {step === 1 && <StepType value={type} onChange={setType} />}
            {step === 2 && (
              <StepAudience
                audienceId={audienceId}
                onAudienceChange={setAudienceId}
                audiences={audienceOptions}
                channels={channels}
                onToggleChannel={toggleChannel}
              />
            )}
            {step === 3 && (
              <StepContent
                channels={channels}
                active={activeChannel}
                onActiveChange={setActiveChannel}
                content={content}
                onChange={setContentKV}
              />
            )}
            {step === 4 && (
              <StepMedia
                selected={selectedMedia}
                onToggle={(id) =>
                  setSelectedMedia((p) => (p.includes(id) ? p.filter((x) => x !== id) : [...p, id]))
                }
              />
            )}
            {step === 5 && (
              <StepSchedule
                date={date}
                onDateChange={setDate}
                sendNow={sendNow}
                onSendNowChange={setSendNow}
                timezone={timezone}
                onTimezoneChange={setTimezone}
                sendTime={sendTime}
                onSendTimeChange={setSendTime}
                throttle={throttle}
                onThrottleChange={setThrottle}
              />
            )}
            {step === 6 && (
              <StepReview
                name={name}
                type={type}
                audience={audience}
                channels={channels}
                content={content}
                selectedMedia={selectedMedia}
                date={date}
                sendNow={sendNow}
                sendTime={sendTime}
                total={total}
                accepted={acceptedCompliance}
                onAcceptedChange={setAcceptedCompliance}
              />
            )}

            <div className="flex items-center justify-between pt-2">
              <Button
                variant="outline"
                size="sm"
                onClick={prev}
                disabled={step === 1}
                className="gap-1.5"
              >
                <ArrowLeft className="h-3.5 w-3.5" /> Back
              </Button>
              {step < 6 ? (
                <Button size="sm" className="gap-1.5" onClick={next}>
                  Continue <ArrowRight className="h-3.5 w-3.5" />
                </Button>
              ) : (
                <Button
                  size="sm"
                  className="gap-1.5"
                  onClick={scheduleCampaign}
                  disabled={!acceptedCompliance || scheduleMutation.isPending}
                >
                  <Rocket className="h-3.5 w-3.5" /> Schedule campaign
                </Button>
              )}
            </div>
          </div>

          <aside className="space-y-4">
            <CostEstimator audienceSize={audienceSize} channels={channels} />
          </aside>
        </div>
      </div>
    </DashboardLayout>
  );
}

/* ---------- Step 1: Type ---------- */
function StepType({ value, onChange }: { value: string; onChange: (v: string) => void }) {
  return (
    <Card>
      <CardHeader>
        <CardTitle className="text-base">Choose a campaign type</CardTitle>
        <CardDescription>
          Pick a starting point. AI Studio will pre-fill copy and recommended channels.
        </CardDescription>
      </CardHeader>
      <CardContent className="grid gap-3 sm:grid-cols-2">
        {CAMPAIGN_TYPES.map((t) => {
          const Icon = t.icon;
          const active = value === t.id;
          return (
            <button
              key={t.id}
              type="button"
              onClick={() => onChange(t.id)}
              className={cn(
                "text-left rounded-lg border p-4 transition-all",
                active ? "border-primary bg-primary/5 shadow-sm" : "hover:border-primary/40",
              )}
            >
              <div className="flex items-start justify-between gap-2">
                <span
                  className={cn(
                    "h-9 w-9 grid place-items-center rounded-md",
                    active
                      ? "bg-primary text-primary-foreground"
                      : "bg-muted text-muted-foreground",
                  )}
                >
                  <Icon className="h-4 w-4" />
                </span>
                {active && <Check className="h-4 w-4 text-primary" />}
              </div>
              <div className="mt-3 font-semibold text-sm">{t.name}</div>
              <div className="text-xs text-muted-foreground mt-1">{t.description}</div>
            </button>
          );
        })}
      </CardContent>
    </Card>
  );
}

/* ---------- Step 2: Audience ---------- */
function StepAudience({
  audienceId,
  onAudienceChange,
  audiences,
  channels,
  onToggleChannel,
}: {
  audienceId: string;
  onAudienceChange: (id: string) => void;
  audiences: Array<(typeof SAVED_AUDIENCES)[number] & { filters?: unknown }>;
  channels: ChannelId[];
  onToggleChannel: (id: ChannelId) => void;
}) {
  return (
    <div className="space-y-4">
      <Card>
        <CardHeader>
          <CardTitle className="text-base">Target audience</CardTitle>
          <CardDescription>
            Pick a saved segment or build a new one in the audience builder.
          </CardDescription>
        </CardHeader>
        <CardContent>
          <RadioGroup value={audienceId} onValueChange={onAudienceChange} className="space-y-2">
            {audiences.map((a) => (
              <label
                key={a.id}
                htmlFor={a.id}
                className={cn(
                  "flex items-center gap-3 rounded-md border p-3 cursor-pointer transition-colors",
                  audienceId === a.id ? "border-primary bg-primary/5" : "hover:border-primary/40",
                )}
              >
                <RadioGroupItem value={a.id} id={a.id} />
                <div className="flex-1 min-w-0">
                  <div className="text-sm font-medium">{a.name}</div>
                  <div className="text-xs text-muted-foreground">{a.description}</div>
                </div>
                <Badge variant="secondary" className="tabular-nums">
                  {formatCount(a.size)}
                </Badge>
              </label>
            ))}
          </RadioGroup>
          <Button variant="outline" size="sm" className="mt-3 gap-1.5" asChild>
            <Link to="/audiences/builder">
              <Sparkles className="h-3.5 w-3.5" /> Build new segment
            </Link>
          </Button>
        </CardContent>
      </Card>

      <Card>
        <CardHeader>
          <CardTitle className="text-base">Select channels</CardTitle>
          <CardDescription>
            Run multi-channel — each will get its own creative editor.
          </CardDescription>
        </CardHeader>
        <CardContent className="grid gap-2 sm:grid-cols-2 lg:grid-cols-3">
          {CHANNELS.map((c) => {
            const active = channels.includes(c.id);
            const Icon = c.icon;
            return (
              <button
                key={c.id}
                type="button"
                onClick={() => onToggleChannel(c.id)}
                className={cn(
                  "flex items-start gap-3 rounded-lg border p-3 text-left transition-all",
                  active ? "border-primary bg-primary/5" : "hover:border-primary/40",
                )}
              >
                <span
                  className={cn(
                    "h-9 w-9 grid place-items-center rounded-md bg-gradient-to-br",
                    c.accent,
                  )}
                >
                  <Icon className="h-4 w-4" />
                </span>
                <div className="flex-1 min-w-0">
                  <div className="flex items-center justify-between">
                    <span className="text-sm font-medium">{c.name}</span>
                    {active && <Check className="h-3.5 w-3.5 text-primary" />}
                  </div>
                  <div className="text-[11px] text-muted-foreground">
                    ₦{c.costPerMessage.toFixed(2)}/{c.unit}
                  </div>
                  <div className="text-[11px] text-muted-foreground mt-0.5 line-clamp-2">
                    {c.description}
                  </div>
                </div>
              </button>
            );
          })}
        </CardContent>
      </Card>
    </div>
  );
}

/* ---------- Step 3: Content ---------- */
function StepContent({
  channels,
  active,
  onActiveChange,
  content,
  onChange,
}: {
  channels: ChannelId[];
  active: ChannelId;
  onActiveChange: (c: ChannelId) => void;
  content: Record<string, string>;
  onChange: (k: string, v: string) => void;
}) {
  if (channels.length === 0) {
    return (
      <Card>
        <CardContent className="py-10 text-center text-sm text-muted-foreground">
          Pick at least one channel in step 2 to configure content.
        </CardContent>
      </Card>
    );
  }
  return (
    <div className="space-y-4">
      <div className="flex flex-wrap items-center gap-1 rounded-md border p-1">
        {channels.map((id) => {
          const meta = CHANNELS.find((c) => c.id === id)!;
          const Icon = meta.icon;
          const a = active === id;
          return (
            <button
              key={id}
              onClick={() => onActiveChange(id)}
              className={cn(
                "flex items-center gap-1.5 px-3 py-1.5 rounded-sm text-xs transition-colors",
                a
                  ? "bg-primary text-primary-foreground"
                  : "text-muted-foreground hover:text-foreground",
              )}
            >
              <Icon className="h-3 w-3" /> {meta.name}
            </button>
          );
        })}
      </div>
      <ChannelConfig channelId={active} content={content} onContentChange={onChange} />
    </div>
  );
}

/* ---------- Step 4: Media ---------- */
function StepMedia({ selected, onToggle }: { selected: string[]; onToggle: (id: string) => void }) {
  return (
    <div className="space-y-4">
      <Card>
        <CardHeader>
          <CardTitle className="text-base">Upload new asset</CardTitle>
          <CardDescription>Images up to 5MB, video up to 25MB, voice up to 5MB.</CardDescription>
        </CardHeader>
        <CardContent>
          <div className="rounded-lg border-2 border-dashed p-8 text-center">
            <Upload className="h-8 w-8 mx-auto text-muted-foreground" />
            <div className="mt-2 text-sm font-medium">Drag & drop or click to upload</div>
            <div className="text-xs text-muted-foreground mt-0.5">JPG · PNG · MP4 · MP3 · WAV</div>
            <Button size="sm" variant="outline" className="mt-3">
              Select file
            </Button>
          </div>
        </CardContent>
      </Card>
      <Card>
        <CardHeader>
          <CardTitle className="text-base">Select from library</CardTitle>
          <CardDescription>{selected.length} asset(s) attached to this campaign.</CardDescription>
        </CardHeader>
        <CardContent>
          <div className="grid gap-3 grid-cols-2 sm:grid-cols-3 lg:grid-cols-4">
            {MEDIA_LIBRARY.map((m) => {
              const Icon = m.type === "image" ? ImageIcon : m.type === "video" ? Video : Mic;
              const isSel = selected.includes(m.id);
              return (
                <button
                  key={m.id}
                  type="button"
                  onClick={() => onToggle(m.id)}
                  className={cn(
                    "rounded-lg border overflow-hidden text-left transition-all",
                    isSel ? "border-primary ring-2 ring-primary/30" : "hover:border-primary/40",
                  )}
                >
                  <div className="aspect-video bg-gradient-to-br from-muted to-muted/50 grid place-items-center relative">
                    <Icon className="h-6 w-6 text-foreground/40" />
                    {isSel && (
                      <span className="absolute top-1.5 right-1.5 h-5 w-5 grid place-items-center rounded-full bg-primary text-primary-foreground">
                        <Check className="h-3 w-3" />
                      </span>
                    )}
                    {m.duration && (
                      <Badge
                        variant="secondary"
                        className="absolute bottom-1.5 right-1.5 text-[9px]"
                      >
                        {m.duration}
                      </Badge>
                    )}
                  </div>
                  <div className="p-2">
                    <div className="text-xs font-medium truncate">{m.name}</div>
                    <div className="text-[10px] text-muted-foreground">{m.size}</div>
                  </div>
                </button>
              );
            })}
          </div>
        </CardContent>
      </Card>
    </div>
  );
}

/* ---------- Step 5: Schedule ---------- */
function StepSchedule({
  date,
  onDateChange,
  sendNow,
  onSendNowChange,
  timezone,
  onTimezoneChange,
  sendTime,
  onSendTimeChange,
  throttle,
  onThrottleChange,
}: {
  date: Date | undefined;
  onDateChange: (d: Date | undefined) => void;
  sendNow: boolean;
  onSendNowChange: (b: boolean) => void;
  timezone: string;
  onTimezoneChange: (s: string) => void;
  sendTime: string;
  onSendTimeChange: (s: string) => void;
  throttle: string;
  onThrottleChange: (s: string) => void;
}) {
  return (
    <Card>
      <CardHeader>
        <CardTitle className="text-base">When should we send?</CardTitle>
        <CardDescription>Schedule a precise time or push out immediately.</CardDescription>
      </CardHeader>
      <CardContent className="space-y-5">
        <div className="flex items-center justify-between rounded-md border p-3">
          <div>
            <div className="text-sm font-medium">Send immediately</div>
            <div className="text-xs text-muted-foreground">
              Mark ready now. Stage 4 still stores the campaign only; no delivery runs.
            </div>
          </div>
          <Switch checked={sendNow} onCheckedChange={onSendNowChange} />
        </div>

        <div
          className={cn("grid gap-3 sm:grid-cols-2", sendNow && "opacity-50 pointer-events-none")}
        >
          <div>
            <Label className="text-xs">Send date</Label>
            <Popover>
              <PopoverTrigger asChild>
                <Button variant="outline" className="mt-1 w-full justify-start gap-2 font-normal">
                  <CalendarDays className="h-3.5 w-3.5" />
                  {date ? format(date, "EEE, MMM d, yyyy") : "Pick a date"}
                </Button>
              </PopoverTrigger>
              <PopoverContent className="w-auto p-0">
                <Calendar mode="single" selected={date} onSelect={onDateChange} />
              </PopoverContent>
            </Popover>
          </div>
          <div>
            <Label className="text-xs">Send time</Label>
            <div className="mt-1 relative">
              <Clock className="absolute left-2.5 top-2.5 h-3.5 w-3.5 text-muted-foreground" />
              <Input
                type="time"
                value={sendTime}
                onChange={(e) => onSendTimeChange(e.target.value)}
                className="pl-8"
              />
            </div>
          </div>
          <div>
            <Label className="text-xs">Timezone</Label>
            <Select value={timezone} onValueChange={onTimezoneChange}>
              <SelectTrigger className="mt-1">
                <SelectValue />
              </SelectTrigger>
              <SelectContent>
                <SelectItem value="Africa/Lagos">Africa/Lagos (WAT)</SelectItem>
                <SelectItem value="Africa/Cairo">Africa/Cairo (EET)</SelectItem>
                <SelectItem value="UTC">UTC</SelectItem>
              </SelectContent>
            </Select>
          </div>
          <div>
            <Label className="text-xs">Delivery cadence</Label>
            <Select value={throttle} onValueChange={onThrottleChange}>
              <SelectTrigger className="mt-1">
                <SelectValue />
              </SelectTrigger>
              <SelectContent>
                <SelectItem value="burst">Burst — under 30 min</SelectItem>
                <SelectItem value="balanced">Balanced — over 2 hours</SelectItem>
                <SelectItem value="trickle">Trickle — across 24 hours</SelectItem>
              </SelectContent>
            </Select>
          </div>
        </div>

        <div className="rounded-md bg-muted/40 p-3 text-xs text-muted-foreground flex gap-2">
          <Sparkles className="h-3.5 w-3.5 text-primary mt-0.5 shrink-0" />
          AI Studio recommends <strong className="text-foreground mx-1">Wed 09:30 WAT</strong> — 18%
          higher open rate for this audience.
        </div>
      </CardContent>
    </Card>
  );
}

/* ---------- Step 6: Review ---------- */
function StepReview({
  name,
  type,
  audience,
  channels,
  content,
  selectedMedia,
  date,
  sendNow,
  sendTime,
  total,
  accepted,
  onAcceptedChange,
}: {
  name: string;
  type: string;
  audience: (typeof SAVED_AUDIENCES)[number];
  channels: ChannelId[];
  content: Record<string, string>;
  selectedMedia: string[];
  date: Date | undefined;
  sendNow: boolean;
  sendTime: string;
  total: number;
  accepted: boolean;
  onAcceptedChange: (b: boolean) => void;
}) {
  const typeName = CAMPAIGN_TYPES.find((t) => t.id === type)?.name ?? type;
  return (
    <div className="space-y-4">
      <Card>
        <CardHeader>
          <CardTitle className="text-base">Review & schedule</CardTitle>
          <CardDescription>
            Confirm details below. Stage 4 stores scheduled campaigns only — no delivery is activated.
          </CardDescription>
        </CardHeader>
        <CardContent className="grid gap-4 sm:grid-cols-2">
          <Field label="Campaign name" value={name} />
          <Field label="Type" value={typeName} />
          <Field label="Audience" value={`${audience.name} · ${formatCount(audience.size)}`} />
          <Field
            label="Channels"
            value={channels.map((c) => CHANNELS.find((x) => x.id === c)?.name).join(" · ") || "—"}
          />
          <Field
            label="Send"
            value={
              sendNow ? "Immediately" : `${date ? format(date, "MMM d, yyyy") : "—"} at ${sendTime}`
            }
          />
          <Field label="Media attached" value={`${selectedMedia.length} asset(s)`} />
          <Field label="Estimated cost" value={formatNaira(total)} highlight />
        </CardContent>
      </Card>

      <Card>
        <CardHeader className="pb-3">
          <CardTitle className="text-sm">Creative previews</CardTitle>
        </CardHeader>
        <CardContent className="space-y-3">
          {channels.map((id) => {
            const meta = CHANNELS.find((c) => c.id === id)!;
            const Icon = meta.icon;
            const preview =
              content[`${id}_body`] ??
              content[
                `${id === "whatsapp" ? "wa_body" : id === "voice" ? "voice_script" : id === "facebook" ? "fb_body" : id === "google" ? "g_desc" : "sms_body"}`
              ] ??
              "—";
            return (
              <div key={id} className="flex gap-3 rounded-md border p-3">
                <span
                  className={cn(
                    "h-8 w-8 shrink-0 grid place-items-center rounded-md bg-gradient-to-br",
                    meta.accent,
                  )}
                >
                  <Icon className="h-4 w-4" />
                </span>
                <div className="min-w-0">
                  <div className="text-xs font-medium">{meta.name}</div>
                  <div className="text-xs text-muted-foreground mt-0.5 whitespace-pre-wrap line-clamp-3">
                    {preview}
                  </div>
                </div>
              </div>
            );
          })}
        </CardContent>
      </Card>

      <Card className="border-warning/40 bg-warning/5">
        <CardContent className="p-4 flex gap-3">
          <AlertTriangle className="h-4 w-4 text-warning shrink-0 mt-0.5" />
          <div className="flex-1 text-xs space-y-2">
            <div className="font-medium text-foreground">Compliance declaration</div>
            <p className="text-muted-foreground">
              I confirm this campaign targets consent-based supporters, complies with INEC §41 and
              the Nigeria Data Protection Act 2023, and includes a clear opt-out path.
            </p>
            <label className="flex items-center gap-2 cursor-pointer">
              <Checkbox checked={accepted} onCheckedChange={(v) => onAcceptedChange(!!v)} />
              <span className="font-medium">I accept the compliance terms</span>
            </label>
          </div>
        </CardContent>
      </Card>
    </div>
  );
}

function Field({ label, value, highlight }: { label: string; value: string; highlight?: boolean }) {
  return (
    <div className="rounded-md border bg-muted/20 p-3">
      <div className="text-[10px] uppercase tracking-wide text-muted-foreground">{label}</div>
      <div className={cn("text-sm font-medium mt-0.5", highlight && "text-base text-primary")}>
        {value}
      </div>
    </div>
  );
}
