import { ThemeControl, useTheme } from "./ThemeProvider";
import { Modal } from "./design-system/Modal";
import { useEffect, useRef, useState } from "react";
import { Check, ChevronDown, Download, Hash, ImageIcon, Send, ShieldCheck } from "lucide-react";
import { Button, Checkbox } from "./design-system/primitives";
import { Field } from "./design-system/Field";
import { habitRequest, type TodayResponse } from "../lib/dashboard";
import { addDays, dayNumber } from "../habits/calendar";
import { renderProgressCard, type CardPrivacy } from "../lib/progress-card";
import type { PublicUser } from "../shared/user";
import type { Delivery, DiscordConnection, ShareData } from "../sharing/contracts";

export function ShareProgress({ user, today, revision, onClose }: { user: PublicUser; today: TodayResponse; revision: number; onClose: () => void }) {
  const { theme } = useTheme();
  const [ids, setIds] = useState(() => today.habits.slice(0, 1).map(h => h.habitId));
  const [thumbnail, setThumbnail] = useState(true);
  const [range, setRange] = useState("30");
  const [from, setFrom] = useState(addDays(today.date, -29));
  const [to, setTo] = useState(today.date);
  const [privacy, setPrivacy] = useState<CardPrivacy>({ name: true, avatar: true, habitNames: true, timezone: false });
  const [card, setCard] = useState<{ key: string; url: string; blob: Blob; alt: string; deliveryId: string; avatarMissing: boolean } | null>(null);
  const [error, setError] = useState("");
  const [renderAttempt, setRenderAttempt] = useState(0);
  const [connection, setConnection] = useState<DiscordConnection | null>(null);
  const [connectionError, setConnectionError] = useState("");
  const [connectionAttempt, setConnectionAttempt] = useState(0);
  const [sending, setSending] = useState(false);
  const [delivery, setDelivery] = useState<(Delivery & { id: string }) | null>(null);
  const [sendError, setSendError] = useState("");
  const lock = useRef(false);
  const lastImage = useRef<{ hash: string; deliveryId: string } | null>(null);
  const key = JSON.stringify({ ids, from, to, privacy, revision, user, theme });
  const ready = card?.key === key ? card : null;
  const sent = ready && delivery?.id === ready.deliveryId ? delivery : null;
  const busy = sending;
  useEffect(() => {
    const controller = new AbortController();
    setConnectionError("");
    setConnection(null);
    habitRequest<DiscordConnection>("/sharing/discord", { signal: controller.signal }).then(value => {
      if (!controller.signal.aborted) setConnection(value);
    }).catch(e => { if (!controller.signal.aborted) setConnectionError(e.message); });
    return () => controller.abort();
  }, [connectionAttempt]);
  useEffect(() => {
    const controller = new AbortController();
    let objectUrl: string | undefined;
    setError(""); setSendError("");
    const timer = setTimeout(async () => {
      if (!ids.length) { setError("Choose at least one habit for your card."); return; }
      if (!from || !to || from > to || to > today.date || dayNumber(to) - dayNumber(from) > 365) { setError("Choose a date range of up to 366 days, ending today or earlier."); return; }
      try {
        const data = await habitRequest<ShareData>("/sharing/preview", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ habitIds: ids, from, to }), signal: controller.signal });
        if (controller.signal.aborted) return;
        const image = await renderProgressCard(data, user, privacy, theme);
        const hash = Array.from(new Uint8Array(await crypto.subtle.digest("SHA-256", await image.blob.arrayBuffer())), byte => byte.toString(16).padStart(2, "0")).join("");
        if (controller.signal.aborted) return;
        objectUrl = URL.createObjectURL(image.blob);
        const deliveryId = lastImage.current?.hash === hash ? lastImage.current.deliveryId : crypto.randomUUID();
        lastImage.current = { hash, deliveryId };
        setCard({ ...image, key, url: objectUrl, deliveryId });
      } catch (e) { if (!controller.signal.aborted) setError(e instanceof Error ? e.message : "Could not create your card."); }
    }, 200);
    return () => { clearTimeout(timer); controller.abort(); if (objectUrl) URL.revokeObjectURL(objectUrl); };
  }, [key, renderAttempt]);

  async function send() {
    if (!ready || !connection?.connected || lock.current || sent) return;
    lock.current = true; setSending(true); setSendError("");
    const form = new FormData(); form.set("deliveryId", ready.deliveryId); form.set("image", ready.blob, "mina-habits-progress.png");
    try { const result = await habitRequest<Delivery>("/sharing/discord/send", { method: "POST", body: form }); setDelivery({ ...result, id: ready.deliveryId }); }
    catch (e) { setSendError(e instanceof Error ? e.message : "Could not send. Retrying this card will not post it twice."); }
    finally { lock.current = false; setSending(false); }
  }
  return (
    <Modal id="share-progress" eyebrow="SHARE A LITTLE PROGRESS" title="Made for your people." description="Choose what to include. See exactly what you’ll share." onClose={onClose} closeLabel="Close sharing" busy={busy} returnFocus={() => document.getElementById("open-sharing")}>
      <div className="ds-share-layout">
        <section className="ds-share-preview-column" aria-label="Card preview">
          <div className="ds-share-preview-heading"><span><ImageIcon size={16} aria-hidden="true" /> Your card</span>
            <div className="ds-share-size" role="group" aria-label="Preview size"><button type="button" aria-pressed={thumbnail} onClick={() => setThumbnail(true)}>Thumbnail</button><button type="button" aria-pressed={!thumbnail} onClick={() => setThumbnail(false)}>Larger</button></div>
          </div>
          <div className={`ds-share-preview${thumbnail ? " ds-share-preview--thumbnail" : ""}`} aria-busy={!ready && !error}>
            {error ? <div className="ds-share-placeholder" role="alert"><ImageIcon size={28} aria-hidden="true" /><p>{error}</p>{ids.length > 0 && <Button variant="secondary" onClick={() => setRenderAttempt(n => n + 1)}>Retry preview</Button>}</div> : ready ? <img src={ready.url} alt={ready.alt} /> : <div className="ds-share-placeholder" role="status"><ImageIcon size={28} aria-hidden="true" /><p>Creating your card…</p></div>}
          </div>
          <p className="ds-share-caption">{thumbnail ? "A small-size preview, like an image in chat." : "A closer look at your card."} Same image in Discord and your download.</p>
          {ready?.avatarMissing && <p role="status" className="ds-share-caption">Your avatar couldn’t load. A neutral profile icon is used.</p>}
        </section>
        <div className="ds-share-controls">
          <ThemeControl disabled={busy} />
          <fieldset className="ds-share-fieldset" disabled={busy}>
            <legend>Time period</legend>
            <div className="ds-share-periods" role="group" aria-label="Date range">{[["7", "7 days"], ["30", "30 days"], ["365", "1 year"], ["custom", "Custom"]].map(([value, label]) => <button key={value} type="button" aria-pressed={range === value} onClick={() => { setRange(value!); if (value !== "custom") { setFrom(addDays(today.date, 1 - Number(value))); setTo(today.date); } }}>{label}</button>)}</div>
            {range === "custom" && <div className="ds-share-dates"><Field label="From">{id => <input id={id} type="date" value={from} max={to || today.date} min="1970-01-01" onChange={e => setFrom(e.target.value)} />}</Field><Field label="To">{id => <input id={id} type="date" value={to} min={from} max={today.date} onChange={e => setTo(e.target.value)} />}</Field></div>}
          </fieldset>
          <fieldset className="ds-share-fieldset" disabled={busy}>
            <legend>Habits <span className="ds-share-count">{ids.length} / 6</span></legend>
            <div className="ds-share-habits">{today.habits.map(habit => <Checkbox key={habit.habitId} label={habit.name ?? "Habit"} checked={ids.includes(habit.habitId)} disabled={!ids.includes(habit.habitId) && ids.length >= 6} onChange={e => setIds(values => e.target.checked ? [...values, habit.habitId] : values.filter(id => id !== habit.habitId))} />)}</div>
            <p className="ds-share-hint">Choose up to six. Task names stay private.</p>
          </fieldset>
          <details className="ds-share-privacy"><summary><ShieldCheck size={17} aria-hidden="true" /><span>Privacy & details</span><ChevronDown size={16} aria-hidden="true" /></summary>
            <fieldset className="ds-share-fieldset" disabled={busy}><legend className="ds-visually-hidden">Show on the card</legend>
              {([["name", "Display name"], ["avatar", "Discord avatar"], ["habitNames", "Habit names"], ["timezone", "Timezone"]] as const).map(([key, label]) => <Checkbox key={key} label={label} checked={privacy[key]} onChange={e => setPrivacy(value => ({ ...value, [key]: e.target.checked }))} />)}
            </fieldset>
          </details>
          <div className="ds-share-destination"><span className="ds-share-destination-icon"><Hash size={20} aria-hidden="true" /></span><div><span className="ds-share-hint">Discord destination</span>
            {connectionError ? <div role="alert"><p>{connectionError}</p><Button variant="text" disabled={busy} onClick={() => setConnectionAttempt(n => n + 1)}>Retry connection</Button></div> : connection?.connected ? <><a href={connection.channelUrl} target="_blank" rel="noreferrer">{connection.name}</a><p className="ds-share-hint">Posted by the Mina Habits bot.</p></> : <p className="ds-share-hint" role="status">{connection?.message ?? "Loading channel…"}</p>}
          </div></div>
        </div>
      </div>
      <footer className="ds-share-footer">
        <div className="ds-share-footer-copy" aria-live="polite">
          {sendError ? <p role="alert" className="ds-share-error">{sendError}</p> : sent ? <p>{sent.status === "sent" ? <>Shared successfully. {sent.messageUrl && <a href={sent.messageUrl} target="_blank" rel="noreferrer">View in Discord ↗</a>}</> : <>Delivery unconfirmed. Check {connection?.channelUrl ? <a href={connection.channelUrl} target="_blank" rel="noreferrer">your channel</a> : "your channel"}; this attempt won’t be resent.</>}</p> : <p>{sending ? "Sending your card to Discord…" : error ? "Check your card settings." : ready ? "Ready when you are." : "Your card is taking shape."}<span>{sending ? "This may take a moment." : "Only the details in your preview are shared."}</span></p>}
        </div>
        <div className="ds-share-actions">
          {ready ? <a className="ds-button ds-button--secondary" href={ready.url} download={`mina-habits-progress-${from}-${to}.png`}><Download size={17} aria-hidden="true" />Download</a> : <Button variant="secondary" disabled><Download size={17} aria-hidden="true" />Download</Button>}
          <Button disabled={!ready || !connection?.connected || busy || !!sent} onClick={() => void send()}>{sent?.status === "sent" ? <Check size={17} aria-hidden="true" /> : <Send size={17} aria-hidden="true" />}{sending ? "Sending…" : sent?.status === "sent" ? "Shared" : sent ? "Check Discord" : "Send to Discord"}</Button>
        </div>
      </footer>
    </Modal>
  );
}
