import { useEffect, useRef, useState } from "react";
import { Download, Send, X } 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 } 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 [ids, setIds] = useState(() => today.habits.slice(0, 1).map(h => h.habitId));
  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 heading = useRef<HTMLHeadingElement>(null);
  const key = JSON.stringify({ ids, from, to, privacy, revision, user });
  const ready = card?.key === key ? card : null;
  const sent = ready && delivery?.id === ready.deliveryId ? delivery : null;
  const busy = sending;
  useEffect(() => { heading.current?.focus(); }, []);
  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; }
      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);
        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, "minabot-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 (
    <section id="share-progress" className="ds-share-panel" aria-labelledby="share-progress-title">
      <header className="ds-share-heading">
        <div><p className="ds-eyebrow">A LITTLE PROGRESS, WORTH SHARING</p><h2 id="share-progress-title" ref={heading} tabIndex={-1} className="type-section">Your progress, in a picture.</h2></div>
        <Button variant="text" disabled={busy} onClick={onClose} aria-label="Close sharing"><X size={20} aria-hidden="true" /></Button>
      </header>
      <div className="ds-share-layout">
        <div className="ds-share-controls">
          <fieldset className="ds-share-fieldset" disabled={busy}>
            <legend className="type-ui-heading">Choose your habits</legend>
            <p className="ds-muted type-small">Up to six per card. Task names are never included.</p>
            <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>
            <Field label="Date range">{id => <select id={id} value={range} onChange={e => { const value = e.target.value; setRange(value); if (value !== "custom") { setFrom(addDays(today.date, 1 - Number(value))); setTo(today.date); } }}><option value="7">Past 7 days</option><option value="30">Past 30 days</option><option value="365">Past year</option><option value="custom">Custom dates</option></select>}</Field>
            {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 className="type-ui-heading">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>
        </div>
        <div className="ds-share-preview-column">
          <div className="ds-share-preview" aria-busy={!ready && !error}>
            {error ? <div role="alert"><p>{error}</p><Button variant="secondary" onClick={() => setRenderAttempt(n => n + 1)}>Retry preview</Button></div> : ready ? <img src={ready.url} alt={ready.alt} /> : <p role="status">Creating your card…</p>}
          </div>
          <p className="type-small ds-muted">This exact image will be downloaded or sent. Days off are excluded from the completion rate.</p>
          {ready?.avatarMissing && <p role="status" className="type-small ds-muted">Your avatar couldn’t load. The card uses a neutral profile icon.</p>}
          <div className="ds-share-actions">
            {ready ? <a className="ds-button ds-button--secondary" href={ready.url} download={`minabot-progress-${from}-${to}.png`}><Download size={17} aria-hidden="true" />Download PNG</a> : <Button variant="secondary" disabled>Download PNG</Button>}
            <Button disabled={!ready || !connection?.connected || busy || !!sent} onClick={() => void send()}><Send size={17} aria-hidden="true" />{sending ? "Sending…" : sent?.status === "sent" ? "Sent to Discord" : sent ? "Check Discord" : "Send to Discord"}</Button>
          </div>
          {connectionError ? <div role="alert" className="ds-share-feedback"><p>{connectionError}</p><Button variant="text" disabled={busy} onClick={() => setConnectionAttempt(n => n + 1)}>Retry Discord</Button></div> : connection?.connected ? <p className="type-small ds-muted">The bot will post this card to <a href={connection.channelUrl} target="_blank" rel="noreferrer">{connection.name}</a>.</p> : <p className="type-small ds-muted" role="status">{connection?.message ?? "Loading the Discord sharing channel…"}</p>}
          {sendError && <p role="alert">{sendError}</p>}
          {sent && <p role="status">{sent.status === "sent" ? <>Your card was sent. {sent.messageUrl && <a href={sent.messageUrl} target="_blank" rel="noreferrer">View in Discord ↗</a>}</> : <>Discord didn’t confirm delivery. Check {connection?.channelUrl ? <a href={connection.channelUrl} target="_blank" rel="noreferrer">your channel</a> : "your channel"} before creating another card; this attempt won’t be resent.</>}</p>}
        </div>
      </div>
    </section>
  );
}
