"use client";

import { useCallback, useEffect, useMemo, useState, useSyncExternalStore, useTransition } from "react";
import { usePathname, useRouter, useSearchParams } from "next/navigation";
import { Button } from "@/components/ui/button";
import { Card } from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { Select } from "@/components/ui/select";
import { Textarea } from "@/components/ui/textarea";
import { cn } from "@/lib/utils";
import { getRegionLabel } from "@/lib/regions";
import { formatMonthLabel } from "@/lib/reports/month";
import { htmlToPlainText, renderRegionSummaryEmailHtml } from "@/lib/reports/region-email";
import { productSplitColors } from "@/lib/reports/region-email";
import type { RegionEmailCountryRow, RegionEmailProductSlice, RegionEmailTrendPoint } from "@/lib/reports/region-email";
import type { RegionEmailPoint } from "@/lib/reports/region-email";
import type { Takeaway } from "@/lib/reports/insights";
import type { RegionEmailStat } from "@/lib/reports/region-email";

type Props = {
  regionCodes: string[];
  availableMonths: string[];
  region: string;
  month: string;
  regionLabel: string;
  monthLabel: string;
  subject: string;
  suggestedBullets: Takeaway[];
  stats: RegionEmailStat[];
  trend: RegionEmailTrendPoint[];
  countryTable: RegionEmailCountryRow[];
  countriesWithoutActivity: string[];
  productSplit: RegionEmailProductSlice[];
};

type Draft = {
  subject?: string;
  // Stored as bullet text, not index: if the underlying data changes the text
  // changes too, and the bullet reappears rather than silently hiding a
  // different one that happened to land at the same position.
  dismissedBullets?: string[];
  customBullets?: string[];
  sent?: boolean;
};

const DRAFT_PREFIX = "otsuka-region-summary";
const DRAFT_EVENT = "otsuka-draft-change";

function draftKey(region: string, month: string) {
  return `${DRAFT_PREFIX}:${region}:${month}`;
}

function subscribeToDrafts(onChange: () => void) {
  window.addEventListener("storage", onChange);
  window.addEventListener(DRAFT_EVENT, onChange);
  return () => {
    window.removeEventListener("storage", onChange);
    window.removeEventListener(DRAFT_EVENT, onChange);
  };
}

// Drafts live in localStorage so switching region/month (or closing the tab)
// never destroys hand-written additions. useSyncExternalStore keeps every
// open tab consistent and avoids a hydration mismatch on first paint.
function useDraftStore() {
  const readAll = useCallback(() => {
    if (typeof window === "undefined") return "{}";
    const entries: Record<string, Draft> = {};
    for (let i = 0; i < window.localStorage.length; i += 1) {
      const key = window.localStorage.key(i);
      if (!key?.startsWith(`${DRAFT_PREFIX}:`)) continue;
      try {
        entries[key] = JSON.parse(window.localStorage.getItem(key) ?? "{}") as Draft;
      } catch {
        // Corrupt entry - ignore it rather than breaking the whole page.
      }
    }
    return JSON.stringify(entries);
  }, []);

  const serialized = useSyncExternalStore(subscribeToDrafts, readAll, () => "{}");
  const drafts = useMemo(() => JSON.parse(serialized) as Record<string, Draft>, [serialized]);

  const saveDraft = useCallback((region: string, month: string, patch: Draft) => {
    const key = draftKey(region, month);
    let current: Draft = {};
    try {
      current = JSON.parse(window.localStorage.getItem(key) ?? "{}") as Draft;
    } catch {
      current = {};
    }
    window.localStorage.setItem(key, JSON.stringify({ ...current, ...patch }));
    window.dispatchEvent(new Event(DRAFT_EVENT));
  }, []);

  return { drafts, saveDraft };
}

function CheckIcon() {
  return (
    <svg viewBox="0 0 16 16" className="h-3 w-3 fill-current" aria-hidden="true">
      <path d="M6.2 11.6 2.9 8.3l1.1-1.1 2.2 2.2 5.8-5.8 1.1 1.1z" />
    </svg>
  );
}

export function RegionSummaryClient({
  regionCodes,
  availableMonths,
  region,
  month,
  regionLabel,
  monthLabel,
  subject,
  suggestedBullets,
  stats,
  trend,
  countryTable,
  countriesWithoutActivity,
  productSplit,
}: Props) {
  const router = useRouter();
  const pathname = usePathname();
  const searchParams = useSearchParams();
  const [isPending, startTransition] = useTransition();
  const { drafts, saveDraft } = useDraftStore();
  const [newBullet, setNewBullet] = useState("");
  const [copyStatus, setCopyStatus] = useState("");

  const draft = drafts[draftKey(region, month)] ?? {};
  const dismissed = useMemo(() => new Set(draft.dismissedBullets ?? []), [draft.dismissedBullets]);
  const customBullets = useMemo(() => draft.customBullets ?? [], [draft.customBullets]);
  const subjectValue = draft.subject ?? subject;

  // Generated points carry their structure into the email renderer; anything the
  // admin typed can only ever be prose. Dismissal still keys on the sentence, so
  // a point whose underlying data changed comes back rather than staying hidden.
  const activeBullets = useMemo<RegionEmailPoint[]>(
    () => [
      ...suggestedBullets.filter((item) => !dismissed.has(item.text)).map((item) => ({ text: item.text, takeaway: item })),
      ...customBullets.map((text) => ({ text })),
    ],
    [suggestedBullets, dismissed, customBullets],
  );

  // Pie drawn on canvas at compose time: pasting the preview into Outlook
  // turns the data-URI image into an embedded inline attachment, which
  // displays by default for recipients - no hosting needed. If drawing fails
  // the renderer falls back to a stacked bar.
  const [pieDataUri, setPieDataUri] = useState<string | undefined>(undefined);
  useEffect(() => {
    if (productSplit.length === 0) {
      setPieDataUri(undefined);
      return;
    }
    const colors = productSplitColors(productSplit);
    const size = 340; // 170px at 2x for crisp paste
    const canvas = document.createElement("canvas");
    canvas.width = size;
    canvas.height = size;
    const ctx = canvas.getContext("2d");
    if (!ctx) return;
    const cx = size / 2;
    const r = size / 2 - 4;
    let angle = -Math.PI / 2;
    for (const slice of productSplit) {
      const sweep = slice.share * Math.PI * 2;
      ctx.beginPath();
      ctx.moveTo(cx, cx);
      ctx.arc(cx, cx, r, angle, angle + sweep);
      ctx.closePath();
      ctx.fillStyle = colors.get(slice.name) ?? "#cbd5e1";
      ctx.fill();
      ctx.strokeStyle = "#ffffff";
      ctx.lineWidth = 3;
      ctx.stroke();
      angle += sweep;
    }
    setPieDataUri(canvas.toDataURL("image/png"));
  }, [productSplit]);

  const emailHtml = useMemo(
    () => (monthLabel ? renderRegionSummaryEmailHtml({ regionLabel, monthLabel, regionCode: region }, activeBullets, stats, trend, countryTable, countriesWithoutActivity, productSplit, pieDataUri) : ""),
    [regionLabel, monthLabel, activeBullets, stats, trend, countryTable, countriesWithoutActivity, productSplit, pieDataUri],
  );

  function updateParam(key: string, value: string) {
    const params = new URLSearchParams(searchParams.toString());
    params.set(key, value);
    setCopyStatus("");
    startTransition(() => {
      router.replace(`${pathname}?${params.toString()}`, { scroll: false });
    });
  }

  function toggleBullet(bullet: string) {
    const next = new Set(dismissed);
    if (next.has(bullet)) {
      next.delete(bullet);
    } else {
      next.add(bullet);
    }
    saveDraft(region, month, { dismissedBullets: [...next] });
  }

  function addCustomBullet() {
    const value = newBullet.trim();
    if (!value) return;
    saveDraft(region, month, { customBullets: [...customBullets, value] });
    setNewBullet("");
  }

  function removeCustomBullet(index: number) {
    saveDraft(region, month, { customBullets: customBullets.filter((_, i) => i !== index) });
  }

  async function copySubject() {
    try {
      await navigator.clipboard.writeText(subjectValue);
      setCopyStatus("Subject copied.");
    } catch {
      setCopyStatus("Couldn't copy - select the subject text and copy manually.");
    }
  }

  async function copyBodyForOutlook() {
    if (!emailHtml) return;
    try {
      await navigator.clipboard.write([
        new ClipboardItem({
          "text/html": new Blob([emailHtml], { type: "text/html" }),
          "text/plain": new Blob([htmlToPlainText(emailHtml)], { type: "text/plain" }),
        }),
      ]);
      setCopyStatus("Email body copied - paste directly into Outlook.");
    } catch {
      setCopyStatus("Couldn't copy automatically - select the preview text and copy manually.");
    }
  }

  const sentCount = regionCodes.filter((code) => drafts[draftKey(code, month)]?.sent).length;

  return (
    <div className="space-y-4">
      <Card className="bg-[linear-gradient(120deg,#ffffff_0%,#f4f9ff_62%,#fff4e9_100%)]">
        <div className="flex flex-wrap items-start justify-between gap-3">
          <div>
            <h2 className="text-xl font-black tracking-tight text-slate-900">Region Summary</h2>
            <p className="mt-2 max-w-2xl text-sm text-slate-600">
              Suggested from the data - untick anything you don&apos;t want, add your own points, then copy
              straight into Outlook. Your edits are saved per region and month. Admin only.
            </p>
          </div>
          <div className="rounded-2xl border border-[#dbe7f5] bg-white/80 px-3 py-2 text-center">
            <p className="caption text-[10px] uppercase tracking-[0.14em] text-slate-500">Sent this month</p>
            <p className="mt-0.5 text-lg font-black text-slate-900">
              {sentCount} / {regionCodes.length}
            </p>
          </div>
        </div>

        <div className="mt-4 max-w-xs">
          <label className="mb-1 block text-[10px] uppercase tracking-[0.14em] text-slate-500">Month</label>
          <Select
            aria-label="Month"
            value={month}
            onChange={(event) => updateParam("month", event.target.value)}
            className="h-11 rounded-xl border-[#ceddee] bg-white text-sm font-medium"
          >
            {availableMonths.map((m) => (
              <option key={m} value={m}>
                {formatMonthLabel(m)}
              </option>
            ))}
          </Select>
        </div>

        <div className="mt-4">
          <p className="mb-2 text-[10px] uppercase tracking-[0.14em] text-slate-500">Region</p>
          <div className="flex flex-wrap gap-2">
            {regionCodes.map((code) => {
              const codeDraft = drafts[draftKey(code, month)];
              const active = code === region;
              return (
                <button
                  key={code}
                  type="button"
                  title={getRegionLabel(code)}
                  onClick={() => updateParam("region", code)}
                  aria-pressed={active}
                  className={cn(
                    "inline-flex items-center gap-1.5 rounded-full border px-3 py-1.5 text-xs font-semibold transition",
                    active
                      ? "border-[#2663AC] bg-[#2663AC] text-white shadow-[0_10px_20px_-14px_rgba(38,99,172,0.9)]"
                      : "border-[#d7e3f1] bg-white text-slate-600 hover:border-[#2663AC]/50 hover:bg-[#f5faff]",
                  )}
                >
                  {codeDraft?.sent ? (
                    <span
                      className={cn(
                        "flex h-4 w-4 items-center justify-center rounded-full",
                        active ? "bg-white/25 text-white" : "bg-emerald-100 text-emerald-700",
                      )}
                    >
                      <CheckIcon />
                    </span>
                  ) : null}
                  {code}
                  {codeDraft?.customBullets?.length ? (
                    <span className={cn("text-[10px]", active ? "text-white/70" : "text-[#c47727]")}>
                      +{codeDraft.customBullets.length}
                    </span>
                  ) : null}
                </button>
              );
            })}
          </div>
        </div>
      </Card>

      {isPending ? (
        <div className="flex items-center gap-3 rounded-2xl border border-[#dbe7f5] bg-white px-5 py-4">
          <span
            className="h-4 w-4 animate-spin rounded-full border-2 border-[#2663AC]/30 border-t-[#2663AC]"
            aria-hidden="true"
          />
          <p className="text-sm font-semibold text-slate-700">Building summary...</p>
        </div>
      ) : !emailHtml ? (
        <div className="rounded-2xl border border-slate-200 bg-white px-6 py-12 text-center text-sm text-slate-500">
          No dated data available yet for this region/month.
        </div>
      ) : (
        <>
          <Card>
            <label className="mb-1 block text-[10px] uppercase tracking-[0.14em] text-slate-500">Subject</label>
            <div className="flex flex-wrap gap-2">
              <Input
                value={subjectValue}
                onChange={(event) => saveDraft(region, month, { subject: event.target.value })}
                className="min-w-[240px] flex-1"
              />
              <Button variant="secondary" onClick={copySubject} className="shrink-0">
                Copy Subject
              </Button>
            </div>
          </Card>

          <Card>
            <h3 className="text-sm font-bold text-slate-900">Points to include</h3>
            <p className="mt-1 text-xs text-slate-500">
              Suggested from this month&apos;s data. Untick to leave one out.
            </p>
            <div className="mt-3 space-y-2">
              {suggestedBullets.map((item) => {
                const bullet = item.text;
                const included = !dismissed.has(bullet);
                return (
                  <label
                    key={bullet}
                    className={cn(
                      "flex cursor-pointer gap-3 rounded-xl border p-3 font-sans text-sm transition",
                      included
                        ? "border-[#d7e3f1] bg-[#f8fbff] text-slate-700"
                        : "border-slate-200 bg-slate-50 text-slate-400 line-through decoration-slate-300",
                    )}
                  >
                    <input
                      type="checkbox"
                      checked={included}
                      onChange={() => toggleBullet(bullet)}
                      className="mt-0.5 h-4 w-4 shrink-0 accent-[#2663AC]"
                    />
                    <span className="leading-relaxed">{bullet}</span>
                  </label>
                );
              })}
            </div>

            <h3 className="mt-5 text-sm font-bold text-slate-900">Your additions</h3>
            <p className="mt-1 text-xs text-slate-500">
              Anything you&apos;ve spotted reviewing their content that the data won&apos;t know about.
            </p>
            {customBullets.length > 0 ? (
              <div className="mt-3 space-y-2">
                {customBullets.map((bullet, index) => (
                  <div
                    key={`${bullet}-${index}`}
                    className="flex items-start gap-3 rounded-xl border border-[#f3d9b8] bg-[#fffaf3] p-3 text-sm text-slate-700"
                  >
                    <span className="mt-1.5 h-1.5 w-1.5 shrink-0 rounded-full bg-[#F7993A]" aria-hidden="true" />
                    <span className="flex-1 leading-relaxed">{bullet}</span>
                    <button
                      type="button"
                      onClick={() => removeCustomBullet(index)}
                      aria-label={`Remove: ${bullet}`}
                      className="shrink-0 rounded-lg px-2 py-0.5 text-xs font-semibold text-slate-400 transition hover:bg-white hover:text-rose-600"
                    >
                      Remove
                    </button>
                  </div>
                ))}
              </div>
            ) : null}
            <div className="mt-3 flex flex-wrap items-end gap-2">
              <Textarea
                value={newBullet}
                onChange={(event) => setNewBullet(event.target.value)}
                onKeyDown={(event) => {
                  if (event.key === "Enter" && (event.metaKey || event.ctrlKey)) {
                    event.preventDefault();
                    addCustomBullet();
                  }
                }}
                rows={2}
                placeholder="Add your own point - ⌘/Ctrl + Enter to add"
                className="min-w-[240px] flex-1"
              />
              <Button variant="secondary" onClick={addCustomBullet} disabled={!newBullet.trim()} className="shrink-0">
                Add point
              </Button>
            </div>
          </Card>

          <Card>
            <div className="flex flex-wrap items-center justify-between gap-3">
              <div>
                <h3 className="text-sm font-bold text-slate-900">Email preview</h3>
                <p className="mt-1 text-xs text-slate-500">
                  Shown at Outlook&apos;s reading width. This is exactly what gets pasted.
                </p>
              </div>
              <div className="flex flex-wrap items-center gap-2">
                <Button
                  variant={draft.sent ? "secondary" : "ghost"}
                  onClick={() => saveDraft(region, month, { sent: !draft.sent })}
                  className="shrink-0"
                >
                  {draft.sent ? "✓ Marked sent" : "Mark as sent"}
                </Button>
                <Button onClick={copyBodyForOutlook} className="shrink-0">
                  Copy for Outlook
                </Button>
              </div>
            </div>
            {copyStatus ? <p className="mt-2 text-xs font-medium text-[#2663AC]">{copyStatus}</p> : null}
            <div className="mt-3 overflow-x-auto rounded-xl border border-dashed border-[#ceddee] bg-white p-4">
              <div
                className="mx-auto w-full max-w-[640px]"
                dangerouslySetInnerHTML={{ __html: emailHtml }}
              />
            </div>
          </Card>
        </>
      )}
    </div>
  );
}
