// ActionMinutes — guided setup: board pick, discovery interview, the equation
const { useState: useStateO, useEffect: useEffectO, useRef: useRefO, useCallback: useCallbackO } = React;

const AM_BOARDS = [
  { ic: "landmark", tt: "City Council", ss: "City / town governing body" },
  { ic: "gavel", tt: "Board of Supervisors", ss: "County governing body" },
  { ic: "users", tt: "Board of Commissioners", ss: "County / district governing body" },
  { ic: "map", tt: "Planning Commission", ss: "Zoning, land use, site plans" },
  { ic: "scale", tt: "Board of Zoning Appeals", ss: "Variances and appeals" },
  { ic: "trees", tt: "Parks & Recreation Board", ss: "Advisory board" },
];

/* ---------- Step 1: pick your board ---------- */
function BoardPickPage({ name, navigate, user, appState, setAppState }) {
  const [boardName, setBoardName] = useStateO("");
  const [custom, setCustom] = useStateO("");
  const [loading, setLoading] = useStateO(false);
  const [error, setError] = useStateO(null);
  const [profile, setProfile] = useStateO(null);
  const [orgBoards, setOrgBoards] = useStateO(AM_BOARDS);

  // Determine what kind of org this is (city / county / …) and lead with their actual governing body.
  useEffectO(() => {
    let active = true;
    AM_API.org.profile().then((p) => {
      if (!active || !p || !p.suggestedBoards || !p.suggestedBoards.length) return;
      setProfile(p);
      setOrgBoards(p.suggestedBoards.map((s) => ({ ic: s.icon, tt: s.name, ss: s.subtitle, gov: s.isGoverningBody })));
      const gov = p.suggestedBoards.find((s) => s.isGoverningBody);
      if (gov) setBoardName((cur) => cur || gov.name);
    }).catch(() => {});
    return () => { active = false; };
  }, []);

  const selected = boardName;
  const first = (user && user.name ? user.name : "there").split(" ")[0];

  const handleContinue = async () => {
    if (!selected || loading) return;
    setLoading(true);
    setError(null);
    try {
      const board = await AM_API.boards.create(selected);
      setAppState((s) => ({ ...s, boardId: board.id, boardName: selected }));
      navigate("/setup/sources");
    } catch (err) {
      setError(err.message || "Could not create board. Please try again.");
    } finally {
      setLoading(false);
    }
  };

  return (
    <div className="am-appmain narrow">
      <SetupSteps current={0} />
      <h2 style={{ fontFamily: "var(--font-display)", fontWeight: 700, fontSize: 24, margin: "0 0 6px" }}>
        Welcome, {first}. Which board or committee should we start with?
      </h2>
      <p style={{ fontSize: 14, color: "var(--fg-2)", margin: "0 0 24px" }}>
        Your credits work for <strong>any</strong> board — let's set up your first one. You can add more later.
      </p>
      {profile && profile.detected && profile.governingBody && (
        <div className="am-domain-note ok" style={{ marginBottom: 16 }}>
          <span className="ico"><AMIcon name="badge-check" size={15} /></span>
          <span>
            Looks like a <strong>{profile.orgType === "District" ? "special district" : profile.orgType.toLowerCase()}</strong>
            {profile.state ? " in " + profile.state : ""} — your governing body is typically the <strong>{profile.governingBody}</strong>.
            We've put it first; pick another if that's not right.
          </span>
        </div>
      )}
      {error && (
        <div className="am-domain-note warn" style={{ marginBottom: 16 }}>
          <span className="ico"><AMIcon name="triangle-alert" size={15} /></span>
          <span>{error}</span>
        </div>
      )}
      <div className="am-board-grid">
        {orgBoards.map((b) => (
          <button key={b.tt} className={"am-board-opt" + (selected === b.tt ? " selected" : "")} onClick={() => { setBoardName(b.tt); setCustom(""); }}>
            <span className="ic"><AMIcon name={b.ic} size={19} /></span>
            <span style={{ minWidth: 0 }}>
              <div className="tt">
                {b.tt}
                {b.gov && <span className="pi-badge pi-badge-info" style={{ marginLeft: 8, fontSize: 10, verticalAlign: "middle" }}>Your governing body</span>}
              </div>
              <div className="ss">{b.ss}</div>
            </span>
          </button>
        ))}
      </div>
      <div className="pi-field" style={{ marginTop: 16 }}>
        <label className="pi-field-label">Or name a different one</label>
        <input
          type="text" placeholder="e.g. County Commission, Quorum Court, Historic Preservation Commission" value={custom}
          onChange={(e) => { setCustom(e.target.value); if (e.target.value) setBoardName(e.target.value); else setBoardName(""); }}
        />
      </div>
      <div style={{ display: "flex", justifyContent: "flex-end", marginTop: 26 }}>
        <button
          className="pi-btn pi-btn-primary pi-btn-lg"
          style={{ opacity: (selected && !loading) ? 1 : 0.45, pointerEvents: (selected && !loading) ? "auto" : "none" }}
          onClick={handleContinue}
        >
          {loading ? "Creating…" : <>Continue <AMIcon name="arrow-right" size={15} /></>}
        </button>
      </div>
    </div>
  );
}

/* ---------- Step 2: discovery interview + live crawler rail ---------- */
function InterviewPage({ name, navigate, appState, setAppState }) {
  const [interview, setInterview] = useStateO({ agendaSystem: "", videoPlatform: "" });
  const [discovery, setDiscovery] = useStateO({ status: "Scanning", statusLine: "", findings: [] });
  const [pollCount, setPollCount] = useStateO(0);
  const boardId = appState.boardId;

  useEffectO(() => {
    if (!boardId) return;
    let cancelled = false;
    const poll = async () => {
      try {
        const data = await AM_API.boards.discovery(boardId);
        if (!cancelled) {
          setDiscovery(data);
          if (data.status !== "Complete" && data.status !== "Failed") {
            setTimeout(() => { if (!cancelled) setPollCount((n) => n + 1); }, 3000);
          }
        }
      } catch (err) {
        // Discovery errors are non-fatal — just stop polling
      }
    };
    poll();
    return () => { cancelled = true; };
  }, [boardId, pollCount]);

  const ready = interview.agendaSystem && interview.videoPlatform;

  const chip = (field, value) => (
    <button
      key={value}
      className={"am-chip" + (interview[field] === value ? " selected" : "")}
      onClick={() => setInterview({ ...interview, [field]: value })}
    >
      {interview[field] === value && <AMIcon name="check" size={13} strokeWidth={3} />}
      {value}
    </button>
  );

  const findings = discovery.findings || [];
  const isScanning = discovery.status !== "Complete" && discovery.status !== "Failed";

  return (
    <div className="am-appmain">
      <SetupSteps current={1} />
      <div className="am-interview">
        <div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
          <div className="pi-card am-q-card">
            <h3 className="am-q">Where do you manage agendas today?</h3>
            <p className="am-q-hint">A best guess is fine — we're already checking what's public.</p>
            <div className="am-chip-grid">
              {["Legistar", "CivicClerk", "Granicus", "Municode", "Our website", "Not sure"].map((v) => chip("agendaSystem", v))}
            </div>
          </div>
          {interview.agendaSystem ? (
            <div className="pi-card am-q-card">
              <h3 className="am-q">Where do your meeting recordings live?</h3>
              <p className="am-q-hint">Wherever the public can watch — we'll handle the rest.</p>
              <div className="am-chip-grid">
                {["YouTube", "Granicus", "PrimeGov", "OneMeeting", "BoxCast", "Facebook"].map((v) => chip("videoPlatform", v))}
              </div>
            </div>
          ) : (
            <div className="pi-card am-q-card" style={{ opacity: 0.45 }}>
              <h3 className="am-q" style={{ color: "var(--fg-3)" }}>Where do your meeting recordings live?</h3>
              <p className="am-q-hint" style={{ margin: 0 }}>Answer the first question to continue.</p>
            </div>
          )}
          <div style={{ display: "flex", justifyContent: "flex-end" }}>
            <button
              className="pi-btn pi-btn-primary pi-btn-lg"
              style={{ opacity: ready ? 1 : 0.45, pointerEvents: ready ? "auto" : "none" }}
              onClick={() => navigate("/setup/equation")}
            >
              {ready ? "See what we found" : "Looking for your sources…"} <AMIcon name="arrow-right" size={15} />
            </button>
          </div>
        </div>

        <aside className="am-crawler">
          <div className="am-crawler-head">
            <span className="am-pulse"></span>
            {isScanning ? "Working in the background" : "Discovery complete"}
          </div>
          {discovery.statusLine && (
            <div className="am-crawler-item" style={{ borderBottom: "none", paddingBottom: 0 }}>
              <span className="st"><span className="am-spin"></span></span>
              <span style={{ opacity: 0.8, fontSize: 12 }}>{discovery.statusLine}</span>
            </div>
          )}
          {findings.length === 0 && isScanning && (
            <div className="am-crawler-item">
              <span className="st"><span className="am-spin"></span></span>
              <span style={{ opacity: 0.7 }}>Scanning your jurisdiction and connected platforms…</span>
            </div>
          )}
          {findings.map((f) => (
            <div className="am-crawler-item" key={f.id}>
              <span className="st">
                <AMIcon name="circle-check" size={14} color="#07AFAA" />
              </span>
              <span>
                <span>
                  Found <strong>{f.title || f.kind}</strong>
                  {f.source ? ` — ${f.source}` : ""}
                </span>
                {f.url && <span className="src">{f.url}</span>}
              </span>
            </div>
          ))}
          {discovery.status === "Failed" && (
            <div className="am-crawler-item">
              <span className="st"><AMIcon name="triangle-alert" size={14} color="#FFC700" /></span>
              <span style={{ opacity: 0.8 }}>Discovery had trouble — you can still continue and fill slots manually.</span>
            </div>
          )}
        </aside>
      </div>
    </div>
  );
}

/* ---------- Step 3: the equation ---------- */
function EquationPage({ name, navigate, appState, setAppState, isStaff }) {
  const [eq, setEq] = useStateO(null);
  const [loading, setLoading] = useStateO(true);
  const [error, setError] = useStateO(null);
  const [confirmOpen, setConfirmOpen] = useStateO(false);
  const [generating, setGenerating] = useStateO(false);
  const [genError, setGenError] = useStateO(null);
  const [urlInputs, setUrlInputs] = useStateO({});
  const [uploading, setUploading] = useStateO({});
  const fileInputRef = useRefO(null);
  const [fileSlot, setFileSlot] = useStateO(null);
  const boardId = appState.boardId;

  const loadEq = async () => {
    if (!boardId) { setLoading(false); return; }
    setLoading(true);
    try {
      const data = await AM_API.boards.equation(boardId);
      setEq(data);
    } catch (err) {
      setError(err.message || "Could not load equation.");
    } finally {
      setLoading(false);
    }
  };

  useEffectO(() => { loadEq(); }, [boardId]);

  const putSlot = async (slot, method, reference, label) => {
    try {
      const updated = await AM_API.equation.putSlot(eq.meetingDraftId, slot, method, reference, label);
      setEq(updated);
    } catch (err) {
      setError(err.message || "Could not update slot.");
    }
  };

  const confirmFinding = async (finding, slotName) => {
    try {
      await AM_API.findings.confirm(finding.id, true);
      await putSlot(slotName, "found", finding.url, finding.title);
    } catch (err) {
      setError(err.message || "Could not confirm finding.");
    }
  };

  const handlePasteUrl = async (slotName) => {
    const url = urlInputs[slotName];
    if (!url) return;
    await putSlot(slotName, "url", url, url);
    setUrlInputs((u) => ({ ...u, [slotName]: "" }));
  };

  const handleFileSelect = async (e) => {
    const file = e.target.files && e.target.files[0];
    if (!file || !fileSlot) return;
    setUploading((u) => ({ ...u, [fileSlot]: true }));
    try {
      const { reference, fileName } = await AM_API.uploadFile(file);
      await putSlot(fileSlot, "upload", reference, fileName);
    } catch (err) {
      setError(err.message || "Upload failed.");
    } finally {
      setUploading((u) => ({ ...u, [fileSlot]: false }));
      setFileSlot(null);
      if (fileInputRef.current) fileInputRef.current.value = "";
    }
  };

  const handleUseStandard = async () => {
    await putSlot("template", "standard", "", "Standard format");
  };

  const handleGenerate = async () => {
    if (!eq || isStaff) return;
    setGenerating(true);
    setGenError(null);
    try {
      const res = await AM_API.generations.create(eq.meetingDraftId);
      setAppState((s) => ({ ...s, generationId: res.generationId }));
      navigate("/jobs/" + res.generationId);
    } catch (err) {
      if (err.status === 402 || (err.body && err.body.error === "no_credits")) {
        setGenError("no_credits");
      } else {
        setGenError(err.message || "Generation failed.");
      }
    } finally {
      setGenerating(false);
      setConfirmOpen(false);
    }
  };

  const slotState = (s) => s && s.state ? s.state : "Missing";

  const slotBadge = (state) => {
    if (state === "Ready") return <span className="pi-badge pi-badge-success"><AMIcon name="check" size={11} strokeWidth={3} /> Ready</span>;
    if (state === "Proposed" || state === "Confirming") return <span className="pi-badge pi-badge-info">Found — confirm</span>;
    if (state === "Processing") return <span className="pi-badge pi-badge-info">Processing…</span>;
    if (state === "Error") return <span className="pi-badge pi-badge-danger">Error</span>;
    return <span className="pi-badge pi-badge-warning">Needed from you</span>;
  };

  const credits = appState.credits || { used: 0, total: 3, remaining: 3, resetsOn: "next month" };
  const allSet = eq && eq.isComplete;

  if (loading) {
    return (
      <div className="am-appmain narrow" style={{ display: "flex", alignItems: "center", justifyContent: "center", minHeight: 320 }}>
        <span className="am-spin" style={{ width: 32, height: 32, borderColor: "rgba(3,149,255,0.2)", borderTopColor: "var(--pi-blue)", display: "inline-block" }}></span>
      </div>
    );
  }

  if (error && !eq) {
    return (
      <div className="am-appmain narrow">
        <SetupSteps current={2} />
        <div className="am-domain-note warn">
          <span className="ico"><AMIcon name="triangle-alert" size={15} /></span>
          <span>{error}</span>
        </div>
        <button className="pi-btn pi-btn-primary" style={{ marginTop: 16 }} onClick={loadEq}>Retry</button>
      </div>
    );
  }

  const agenda = eq && eq.agenda;
  const video = eq && eq.video;
  const template = eq && eq.template;
  const meetingTitle = eq && eq.meetingTitle ? eq.meetingTitle : "Meeting";
  const meetingDate = eq && eq.meetingDate ? new Date(eq.meetingDate).toLocaleDateString("en-US", { month: "long", day: "numeric", year: "numeric" }) : "";
  const boardName = appState.boardName || "your board";

  const renderSlotActions = (slotName, slotData, labelIcon) => {
    const state = slotState(slotData);
    const isReady = state === "Ready";
    const label = slotData && slotData.label ? slotData.label : "";
    const source = slotData && slotData.reference ? slotData.reference : "";

    if (isReady) {
      return (
        <span className="am-q-done">
          <AMIcon name="circle-check" size={15} color="#07AFAA" />
          {label || "Confirmed"}{source && <span style={{ color: "var(--fg-3)", fontFamily: "var(--font-mono)", fontSize: 11, marginLeft: 6 }}>{source.length > 60 ? source.slice(0, 60) + "…" : source}</span>}
        </span>
      );
    }

    if (state === "Proposed" || state === "Confirming") {
      return (
        <React.Fragment>
          <button className="pi-btn pi-btn-primary" onClick={() => confirmFinding({ id: slotData.id || slotData.reference, url: slotData.reference }, slotName)}>Yes, use this</button>
          <button className="pi-btn pi-btn-ghost" onClick={() => setUrlInputs((u) => ({ ...u, [slotName]: "" }))}>Not right</button>
          <span className="am-slot-manual">or <a href="#" onClick={(e) => { e.preventDefault(); setUrlInputs((u) => ({ ...u, [slotName]: u[slotName] !== undefined ? u[slotName] : "" })); }}>paste a URL</a></span>
        </React.Fragment>
      );
    }

    return (
      <React.Fragment>
        {urlInputs[slotName] !== undefined ? (
          <div style={{ display: "flex", gap: 8, alignItems: "center", width: "100%" }}>
            <input
              type="text" placeholder="https://…" value={urlInputs[slotName]}
              style={{ flex: 1, fontFamily: "var(--font-mono)", fontSize: 12, border: "1px solid var(--border-1)", borderRadius: "var(--radius-md)", padding: "8px 10px" }}
              onChange={(e) => setUrlInputs((u) => ({ ...u, [slotName]: e.target.value }))}
            />
            <button className="pi-btn pi-btn-primary" onClick={() => handlePasteUrl(slotName)}>Use this URL</button>
            <button className="pi-btn pi-btn-ghost" onClick={() => setUrlInputs((u) => { const n = { ...u }; delete n[slotName]; return n; })}>Cancel</button>
          </div>
        ) : (
          <React.Fragment>
            {slotName === "template" ? (
              <React.Fragment>
                <button className="pi-btn pi-btn-ghost" onClick={() => { setFileSlot("template"); if (fileInputRef.current) fileInputRef.current.click(); }}>
                  <AMIcon name="upload" size={14} /> {uploading.template ? "Uploading…" : "Upload file"}
                </button>
                <button className="pi-btn pi-btn-ghost" onClick={handleUseStandard}>Use standard format</button>
                <span className="am-slot-manual">or <a href="#" onClick={(e) => { e.preventDefault(); setUrlInputs((u) => ({ ...u, template: "" })); }}>paste a URL</a></span>
              </React.Fragment>
            ) : (
              <React.Fragment>
                <button className="pi-btn pi-btn-ghost" onClick={() => setUrlInputs((u) => ({ ...u, [slotName]: "" }))}>
                  Paste a URL
                </button>
                {slotName === "agenda" && (
                  <button className="pi-btn pi-btn-ghost" onClick={() => { setFileSlot("agenda"); if (fileInputRef.current) fileInputRef.current.click(); }}>
                    <AMIcon name="upload" size={14} /> Upload file
                  </button>
                )}
              </React.Fragment>
            )}
          </React.Fragment>
        )}
      </React.Fragment>
    );
  };

  return (
    <div className="am-appmain narrow">
      <SetupSteps current={2} />
      <h2 style={{ fontFamily: "var(--font-display)", fontWeight: 700, fontSize: 24, margin: "0 0 6px" }}>
        Here's the equation for your first minutes
      </h2>
      <p style={{ fontSize: 14, color: "var(--fg-2)", margin: "0 0 24px" }}>
        {boardName}{meetingDate && <React.Fragment> · meeting of <strong>{meetingDate}</strong></React.Fragment>}. Confirm each piece — or swap in your own.
      </p>

      {error && (
        <div className="am-domain-note warn" style={{ marginBottom: 16 }}>
          <span className="ico"><AMIcon name="triangle-alert" size={15} /></span>
          <span>{error}</span>
        </div>
      )}

      <input ref={fileInputRef} type="file" style={{ display: "none" }} onChange={handleFileSelect} accept=".pdf,.doc,.docx" />

      <div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
        {/* Agenda slot */}
        <div className={"am-slot-card" + (slotState(agenda) === "Ready" ? " confirmed" : "")}>
          <span className="am-slot-icon"><AMIcon name="file-text" size={20} /></span>
          <div className="am-slot-body">
            <div className="am-slot-kicker">Agenda {slotBadge(slotState(agenda))}</div>
            <div className="am-slot-title">{agenda && agenda.label ? agenda.label : "Agenda for this meeting"}</div>
            {agenda && agenda.reference && (
              <div className="am-slot-sub" style={{ fontFamily: "var(--font-mono)", fontSize: 11 }}>{agenda.reference}</div>
            )}
            <div className="am-slot-actions">
              {renderSlotActions("agenda", agenda)}
            </div>
          </div>
        </div>

        {/* Video slot */}
        <div className={"am-slot-card" + (slotState(video) === "Ready" ? " confirmed" : "")}>
          <span className="am-slot-icon"><AMIcon name="video" size={20} /></span>
          <div className="am-slot-body">
            <div className="am-slot-kicker">Recording {slotBadge(slotState(video))}</div>
            <div className="am-slot-title">{video && video.label ? video.label : "Meeting recording"}</div>
            {video && video.reference && (
              <div className="am-slot-sub" style={{ fontFamily: "var(--font-mono)", fontSize: 11 }}>{video.reference}</div>
            )}
            <div className="am-slot-actions">
              {renderSlotActions("video", video)}
            </div>
          </div>
        </div>

        {/* Template slot */}
        <div className={"am-slot-card" + (slotState(template) === "Ready" ? " confirmed" : "")}>
          <span className="am-slot-icon"><AMIcon name="file-check" size={20} /></span>
          <div className="am-slot-body">
            <div className="am-slot-kicker">Your minutes template {slotBadge(slotState(template))}</div>
            <div className="am-slot-title">{template && template.label ? template.label : "An example of your ideal approved minutes"}</div>
            <div className="am-slot-sub">We'll match your board's structure and voice — motions, votes, phrasing, all of it.</div>
            <div className="am-slot-actions">
              {renderSlotActions("template", template)}
            </div>
          </div>
        </div>
      </div>

      <div className="am-generate-bar">
        <div>
          <div className="tt">{allSet ? "Your equation is complete." : "Complete all three to generate."}</div>
          <div className="ss">Agenda + Recording + Your template = Your minutes · This will use <strong style={{ color: "#84D0F7" }}>1 of your {credits.remaining} remaining</strong> monthly credits.</div>
        </div>
        {!isStaff && (
          <button
            className="pi-btn pi-btn-primary pi-btn-lg"
            style={{ opacity: allSet ? 1 : 0.4, pointerEvents: allSet ? "auto" : "none", flexShrink: 0 }}
            onClick={() => setConfirmOpen(true)}
          >
            <AMIcon name="sparkles" size={15} /> Generate draft minutes
          </button>
        )}
      </div>

      {confirmOpen && (
        <AMModal
          title="Use 1 meeting credit?"
          onClose={() => setConfirmOpen(false)}
          footer={
            <React.Fragment>
              <button className="pi-btn pi-btn-ghost" onClick={() => setConfirmOpen(false)}>Not yet</button>
              <button className="pi-btn pi-btn-primary" onClick={handleGenerate} disabled={generating}>
                <AMIcon name="sparkles" size={14} /> {generating ? "Queuing…" : "Generate draft minutes"}
              </button>
            </React.Fragment>
          }
        >
          <div style={{ display: "flex", alignItems: "center", gap: 14 }}>
            <CreditsPill used={credits.used} allowance={credits.total} resetLabel={credits.resetsOn || "next month"} />
            <span style={{ fontSize: 13, color: "var(--fg-2)" }}>you'll have <strong>{Math.max(0, credits.remaining - 1)}</strong> left this month</span>
          </div>
          <p style={{ fontSize: 13.5, color: "var(--fg-2)", margin: 0, lineHeight: 1.55 }}>
            We'll draft minutes for the <strong>{boardName} meeting{meetingDate && ` of ${meetingDate}`}</strong> using your template.
            If anything goes wrong on our end, the credit comes right back.
          </p>
          {genError === "no_credits" && (
            <div className="am-domain-note warn">
              <span className="ico"><AMIcon name="triangle-alert" size={15} /></span>
              <span>You're out of credits for this month. They'll reset soon, or talk to our team to get more.</span>
            </div>
          )}
          {genError && genError !== "no_credits" && (
            <div className="am-domain-note warn">
              <span className="ico"><AMIcon name="triangle-alert" size={15} /></span>
              <span>{genError}</span>
            </div>
          )}
        </AMModal>
      )}
    </div>
  );
}

Object.assign(window, { BoardPickPage, InterviewPage, EquationPage });
