/* Team Meetings tab.
 *
 * Three states:
 *   list      — past meetings with quick stats + Start meeting CTA
 *   recording — full-bleed black recording surface with timer, agenda
 *               taps, autosave indicator
 *   review    — structured-output form (editable) once Haiku has parsed
 *
 * Robustness baked in (spec section 4.6.2):
 *   - chunked uploads as audio is recorded so a crash mid-meeting still
 *     leaves recoverable audio in Storage.
 *   - beforeunload guard while recording.
 *   - Wake Lock acquired on Start (where supported) so the screen
 *     stays awake during a 60-min meeting.
 *   - Resume prompt on app load if a meeting was started but never ended.
 *   - Failure recovery: transcribe again / fill structured fields by hand.
 */
(function () {
  const { useState, useEffect, useRef, useMemo, useCallback } = React;
  const {
    Card,
    Button,
    Drawer,
    Input,
    TextArea,
    Pill,
    Icons,
    EmptyState,
    LoadingSpinner,
    Banner,
    showToast,
    fb,
    api,
    coach,
    meetings,
    entries,
    recorder,
    time,
    tokens,
  } = window.CC;

  // ────────────────────────────────────────────────────────────
  // Tab root
  // ────────────────────────────────────────────────────────────
  function Meetings({ initialState = "list" }) {
    const [state, setState] = useState(initialState);
    const [activeMeeting, setActiveMeeting] = useState(null); // recording or review
    const [pastList, setPastList] = useState(meetings.all());
    const [resumeFor, setResumeFor] = useState(null);

    useEffect(() => meetings.subscribe(setPastList), []);

    // On boot — check for an in-progress meeting we can resume.
    useEffect(() => {
      const draft = JSON.parse(localStorage.getItem("cc.meeting.draft") || "null");
      if (draft && draft.id && Date.now() - draft.created_at < 12 * 60 * 60 * 1000) {
        setResumeFor(draft);
      }
    }, []);

    function start() {
      const id = fb.newMeetingId();
      const now = Date.now();
      const draft = {
        id,
        created_at: now,
        attendees: [coach.get() || "simon"],
        audio_path: null,
        audio_duration_sec: null,
        transcript: "",
        agenda_taps: [],
        structured: null,
        carryover_status: {},
        notes: null,
        deleted: false,
      };
      meetings.set(id, draft);
      localStorage.setItem("cc.meeting.draft", JSON.stringify(draft));
      setActiveMeeting(draft);
      setState("recording");
    }

    if (state === "recording" && activeMeeting) {
      return (
        <RecordingView
          meeting={activeMeeting}
          onEnd={(updated) => {
            setActiveMeeting(updated);
            setState("review");
          }}
          onCancel={() => {
            localStorage.removeItem("cc.meeting.draft");
            setActiveMeeting(null);
            setState("list");
          }}
        />
      );
    }

    if (state === "review" && activeMeeting) {
      return (
        <ReviewView
          meeting={activeMeeting}
          onClose={() => {
            localStorage.removeItem("cc.meeting.draft");
            setActiveMeeting(null);
            setState("list");
          }}
        />
      );
    }

    // list
    return (
      <div className="cc-meet">
        <header className="cc-events__head">
          <h1 className="cc-hub__title">Team meetings</h1>
        </header>

        {resumeFor && (
          <Banner
            tone="warning"
            message={`A meeting from ${time.relative(resumeFor.created_at)} is still in progress.`}
            action={{
              label: "Resume",
              onClick: () => {
                setActiveMeeting(resumeFor);
                setState("recording");
                setResumeFor(null);
              },
            }}
            onDismiss={() => {
              localStorage.removeItem("cc.meeting.draft");
              setResumeFor(null);
            }}
          />
        )}

        <Button size="xl" fullWidth onClick={start}>
          {Icons.mic(20)} Start meeting
        </Button>

        <h2 className="cc-section-h2" style={{ marginTop: 32 }}>
          Past
        </h2>
        {pastList.filter((m) => !m.deleted).length === 0 ? (
          <EmptyState
            icon={Icons.mic(40)}
            title="No meetings recorded yet"
            subtitle={`Tap Start meeting when you’re with ${coach.label(coach.other(coach.get() || "simon"))}.`}
          />
        ) : (
          <div className="cc-meet__list">
            {pastList
              .filter((m) => !m.deleted && m.structured)
              .map((m) => (
                <MeetingCard
                  key={m.id}
                  meeting={m}
                  onOpen={() => {
                    setActiveMeeting(m);
                    setState("review");
                  }}
                />
              ))}
          </div>
        )}
      </div>
    );
  }

  // ────────────────────────────────────────────────────────────
  // Past meeting card
  // ────────────────────────────────────────────────────────────
  function MeetingCard({ meeting, onOpen }) {
    const date = new Date(meeting.created_at);
    const day = String(date.getDate()).padStart(2, "0");
    const month = date.toLocaleDateString(undefined, { month: "short" });
    const openCount =
      (meeting.structured?.action_items?.filter((a) => !a.completed).length || 0) +
      (meeting.structured?.open_questions?.length || 0);
    const firstTopic = meeting.structured?.topics?.[0] || "—";

    return (
      <Card variant="elevated" padding={20} onClick={onOpen}>
        <div className="cc-meet-card">
          <div className="cc-meet-card__date">
            <span className="cc-meet-card__day">{day}</span>
            <span className="cc-meet-card__month">{month}</span>
          </div>
          <div className="cc-meet-card__body">
            <div className="cc-meet-card__attendees">
              {(meeting.attendees || []).map(coach.label).join(", ")}
            </div>
            <div className="cc-meet-card__topic">{firstTopic}</div>
          </div>
          {openCount > 0 && (
            <Pill tone="overdue">{openCount} open</Pill>
          )}
        </div>
      </Card>
    );
  }

  // ────────────────────────────────────────────────────────────
  // Recording view
  // ────────────────────────────────────────────────────────────
  function RecordingView({ meeting, onEnd, onCancel }) {
    const [agenda, setAgenda] = useState([]);
    const [carryover, setCarryover] = useState([]);
    const [activeSection, setActiveSection] = useState(null);
    const [visited, setVisited] = useState(() => new Set());
    const [elapsed, setElapsed] = useState(0);
    const [chunkCount, setChunkCount] = useState(0);
    const [stopping, setStopping] = useState(false);
    const [savedChunks, setSavedChunks] = useState(0);
    const recRef = useRef(null);
    const wakeRef = useRef(null);

    // Load agenda + carryover.
    useEffect(() => {
      meetings.loadAgendaTemplate().then((sections) => setAgenda(sections));
      setCarryover(meetings.carryover());
    }, []);

    // Start recording on mount; stop + cleanup on unmount.
    useEffect(() => {
      let cancelled = false;
      (async () => {
        const r = new recorder.Recorder({
          chunkMs: 5000,
          onElapsed: (s) => setElapsed(s),
          onChunk: async (blob, count) => {
            setChunkCount(count);
            // Eager upload of each chunk as a separate object — gives us
            // recoverable audio even if the merged finalisation fails.
            const path = `audio/meetings/${meeting.id}/chunk-${String(count).padStart(4, "0")}.webm`;
            try {
              await fb.uploadAudio(path, blob);
              setSavedChunks((c) => c + 1);
            } catch (e) {
              console.warn("chunk upload failed", e);
            }
          },
        });
        try {
          await r.start();
        } catch (e) {
          if (!cancelled) {
            showToast(e.code === "denied" ? "Mic denied. Cannot record meeting." : "Couldn’t start recording.");
            onCancel();
          }
          return;
        }
        if (cancelled) {
          r.cancel();
          return;
        }
        recRef.current = r;
        // Wake lock (best-effort).
        if ("wakeLock" in navigator) {
          try {
            wakeRef.current = await navigator.wakeLock.request("screen");
          } catch {}
        }
      })();

      // Block accidental tab close.
      const guard = (e) => {
        e.preventDefault();
        e.returnValue = "";
        return "";
      };
      window.addEventListener("beforeunload", guard);

      return () => {
        cancelled = true;
        window.removeEventListener("beforeunload", guard);
        if (recRef.current) recRef.current.cancel();
        if (wakeRef.current?.release) wakeRef.current.release().catch(() => {});
      };
    }, []);

    function tap(section) {
      setActiveSection(section);
      setVisited((v) => new Set(v).add(section.id));
      meetings.logAgendaTap(meeting.id, section.id, elapsed);
    }

    async function finish() {
      if (stopping) return;
      setStopping(true);

      const r = recRef.current;
      if (!r) {
        onCancel();
        return;
      }
      const result = await r.stop();
      const finalPath = `audio/meetings/${meeting.id}.webm`;
      let audio_path = null;
      try {
        const up = await fb.uploadAudio(finalPath, result.blob);
        audio_path = up.path;
      } catch (e) {
        console.warn("final audio upload failed; falling back to chunks", e);
      }

      // Transcribe.
      let transcript = "";
      try {
        const tr = await api.transcribeAudio({
          audioPath: audio_path,
          durationSec: result.durationSec,
        });
        transcript = tr.text || "";
      } catch (e) {
        console.warn("transcribe failed", e);
      }

      // Parse via Haiku.
      const parseResult = await api.parseMeeting({
        transcript,
        agenda_template: agenda,
        agenda_taps: meeting.agenda_taps || [],
        carryover_items: carryover,
      });

      const updated = {
        ...meeting,
        audio_path,
        audio_duration_sec: Math.round(result.durationSec),
        transcript,
        structured: parseResult.parsed || {
          topics: [],
          decisions: [],
          action_items: [],
          things_to_improve: [],
          open_questions: [],
          carryover_status: {},
        },
        parse_raw: parseResult.parsed ? null : parseResult.raw,
      };
      await meetings.set(meeting.id, updated);
      onEnd(updated);
    }

    const sections = [
      ...(carryover.length > 0
        ? [{
            id: "carryover",
            title: "Carryover from last meeting",
            items: carryover.map((c) => c.text),
          }]
        : []),
      ...agenda.map((s) => ({ ...s })),
    ];
    const visitedCount = visited.size;

    return (
      <div className="cc-rec">
        <header className="cc-rec__top">
          <button type="button" className="cc-rec__cancel" onClick={onCancel}>
            Cancel
          </button>
          <div className="cc-rec__autosave" aria-live="polite">
            <span className={`cc-rec__dot ${savedChunks ? "is-saved" : ""}`} />
            {savedChunks > 0
              ? `auto-saved · ${savedChunks}/${chunkCount} chunks`
              : "auto-saving…"}
          </div>
        </header>

        <div className="cc-rec__timer">
          <span className="cc-rec__pulse" aria-hidden="true" />
          <span>{time.audioDuration(elapsed)}</span>
        </div>

        <div className="cc-rec__active">
          <span className="cc-rec__active-label">Current section</span>
          <span className="cc-rec__active-title">
            {activeSection ? activeSection.title : "Tap a section to start"}
          </span>
        </div>

        <ul className="cc-rec__agenda">
          {sections.map((s) => {
            const isActive = activeSection?.id === s.id;
            return (
              <li key={s.id}>
                <button
                  type="button"
                  className={`cc-rec__section ${isActive ? "is-active" : ""} ${
                    visited.has(s.id) ? "is-visited" : ""
                  }`}
                  onClick={() => tap(s)}
                >
                  <span className="cc-rec__section-title">{s.title}</span>
                  {Array.isArray(s.items) && s.items.length > 0 && (
                    <ul className="cc-rec__section-items">
                      {s.items.map((it, i) => (
                        <li key={i}>{it}</li>
                      ))}
                    </ul>
                  )}
                  {visited.has(s.id) && (
                    <span className="cc-rec__check">{Icons.check(14)}</span>
                  )}
                </button>
              </li>
            );
          })}
        </ul>

        <div className="cc-rec__foot">
          <span className="cc-rec__count">
            {visitedCount}/{sections.length} sections covered
          </span>
          <button
            type="button"
            className="cc-rec__end"
            onClick={finish}
            disabled={stopping}
          >
            {stopping ? "Processing…" : "End meeting"}
          </button>
        </div>
      </div>
    );
  }

  // ────────────────────────────────────────────────────────────
  // Review view
  // ────────────────────────────────────────────────────────────
  function ReviewView({ meeting, onClose }) {
    const [draft, setDraft] = useState(() => normalise(meeting));
    const [audioUrl, setAudioUrl] = useState(null);
    const [showTranscript, setShowTranscript] = useState(false);
    const me = coach.get() || "simon";
    const carryover = meetings.carryover();
    const date = new Date(meeting.created_at);

    useEffect(() => {
      if (!meeting.audio_path) return;
      fb.storage
        .ref(meeting.audio_path)
        .getDownloadURL()
        .then(setAudioUrl)
        .catch(() => setAudioUrl(null));
    }, [meeting.audio_path]);

    function patchStructured(p) {
      setDraft((d) => ({ ...d, structured: { ...d.structured, ...p } }));
    }

    async function save() {
      // Persist the meeting itself first.
      await meetings.update(meeting.id, {
        structured: draft.structured,
        notes: draft.notes || null,
      });

      // Decisions + uncompleted action items become Knowledge Hub
      // entries (type: note, tag: decision) for Attention.
      const allItems = [
        ...(draft.structured.decisions || []).map((text) => ({
          body: text,
          tag: "decision",
          needs_followup: false,
        })),
        ...(draft.structured.action_items || [])
          .filter((a) => !a.completed)
          .map((a) => ({
            body: `[${a.owner || "both"}] ${a.text}`,
            tag: "decision",
            needs_followup: true,
          })),
      ];
      for (const it of allItems) {
        const id = fb.newEntryId();
        await fb.set(`entries/${id}`, {
          id,
          type: "note",
          coach: me,
          created_at: Date.now(),
          body: it.body,
          transcript: null,
          audio_path: null,
          audio_duration_sec: null,
          members: [],
          tag: it.tag,
          needs_followup: it.needs_followup,
          pinned: false,
          pinned_by: null,
          mentions: [],
          edited_at: null,
          deleted: false,
          meeting_id: meeting.id,
          meeting_decision: true,
        });
      }
      showToast("Meeting saved.");
      onClose();
    }

    async function del() {
      await meetings.softDelete(meeting.id);
      showToast("Meeting deleted.", {
        action: {
          label: "Undo",
          onClick: () => meetings.update(meeting.id, { deleted: false }),
        },
      });
      onClose();
    }

    return (
      <div className="cc-meet">
        <header className="cc-meet-review__head">
          <button
            type="button"
            className="cc-member-detail__back"
            onClick={onClose}
          >
            ← Meetings
          </button>
          <h1 className="cc-member-detail__name">
            {date.toLocaleDateString(undefined, {
              weekday: "long",
              day: "numeric",
              month: "long",
            })}
          </h1>
          <div className="cc-member-detail__meta">
            <span>
              {(meeting.attendees || []).map(coach.label).join(", ")}
            </span>
            {meeting.audio_duration_sec ? (
              <span>· {time.audioDuration(meeting.audio_duration_sec)}</span>
            ) : null}
          </div>
        </header>

        {meeting.parse_raw && (
          <Banner
            tone="warning"
            message="Couldn’t auto-structure this meeting — fill in the fields below by hand."
          />
        )}

        <Section title="Topics discussed">
          <BulletEditor
            items={draft.structured.topics || []}
            onChange={(v) => patchStructured({ topics: v })}
            placeholder="Add a topic"
          />
        </Section>

        <Section
          title="Decisions"
          hint="Save adds these to Knowledge Hub → Attention → Decisions."
        >
          <BulletEditor
            items={draft.structured.decisions || []}
            onChange={(v) => patchStructured({ decisions: v })}
            placeholder="Add a decision"
          />
        </Section>

        <Section title="Action items">
          <ActionEditor
            items={draft.structured.action_items || []}
            onChange={(v) => patchStructured({ action_items: v })}
          />
        </Section>

        <Section title="Things to improve">
          <BulletEditor
            items={draft.structured.things_to_improve || []}
            onChange={(v) => patchStructured({ things_to_improve: v })}
            placeholder="Add an improvement"
          />
        </Section>

        <Section
          title="Open questions"
          hint="These appear at the top of your next meeting’s carryover."
        >
          <BulletEditor
            items={draft.structured.open_questions || []}
            onChange={(v) => patchStructured({ open_questions: v })}
            placeholder="Add a question"
          />
        </Section>

        {carryover.length > 0 && (
          <Section title="Carryover from last meeting">
            <CarryoverEditor
              items={carryover}
              status={draft.structured.carryover_status || {}}
              onChange={(v) => patchStructured({ carryover_status: v })}
            />
          </Section>
        )}

        {audioUrl && (
          <Section title="Audio" collapsible>
            <audio src={audioUrl} controls preload="none" style={{ width: "100%" }} />
          </Section>
        )}

        {meeting.transcript && (
          <details
            className="cc-meet-review__transcript"
            open={showTranscript}
            onToggle={(e) => setShowTranscript(e.target.open)}
          >
            <summary>Full transcript</summary>
            <pre>{meeting.transcript}</pre>
          </details>
        )}

        <div className="cc-meet-review__foot">
          <Button variant="ghost" onClick={del}>
            {Icons.trash(14)} Delete
          </Button>
          <span style={{ flex: 1 }} />
          <Button variant="secondary" onClick={onClose}>
            Cancel
          </Button>
          <Button onClick={save}>Save</Button>
        </div>
      </div>
    );
  }

  function normalise(meeting) {
    const s = meeting.structured || {};
    return {
      ...meeting,
      structured: {
        topics: s.topics || [],
        decisions: s.decisions || [],
        action_items: s.action_items || [],
        things_to_improve: s.things_to_improve || [],
        open_questions: s.open_questions || [],
        carryover_status: s.carryover_status || {},
      },
    };
  }

  function Section({ title, hint, collapsible = false, children }) {
    if (collapsible) {
      return (
        <details className="cc-meet-review__section">
          <summary>{title}</summary>
          {children}
        </details>
      );
    }
    return (
      <section className="cc-meet-review__section">
        <h2 className="cc-section-h2">{title}</h2>
        {hint && <p className="cc-meet-review__hint">{hint}</p>}
        {children}
      </section>
    );
  }

  function BulletEditor({ items, onChange, placeholder }) {
    const [draft, setDraft] = useState("");
    function add() {
      const v = draft.trim();
      if (!v) return;
      onChange([...items, v]);
      setDraft("");
    }
    function patch(i, v) {
      const out = items.slice();
      out[i] = v;
      onChange(out);
    }
    function remove(i) {
      onChange(items.filter((_, j) => j !== i));
    }
    return (
      <ul className="cc-meet-review__list">
        {items.map((it, i) => (
          <li key={i}>
            <Input value={it} onChange={(v) => patch(i, v)} />
            <button
              type="button"
              className="cc-meet-review__rm"
              onClick={() => remove(i)}
              aria-label="Remove"
            >
              {Icons.x(14)}
            </button>
          </li>
        ))}
        <li>
          <Input
            value={draft}
            onChange={setDraft}
            placeholder={placeholder}
            onSubmit={add}
          />
          <button
            type="button"
            className="cc-meet-review__add"
            onClick={add}
            disabled={!draft.trim()}
          >
            {Icons.plus(14)}
          </button>
        </li>
      </ul>
    );
  }

  function ActionEditor({ items, onChange }) {
    function patch(i, p) {
      const out = items.slice();
      out[i] = { ...out[i], ...p };
      onChange(out);
    }
    function remove(i) {
      onChange(items.filter((_, j) => j !== i));
    }
    function add() {
      onChange([...items, { owner: "both", text: "", due_date: null, completed: false }]);
    }
    return (
      <ul className="cc-meet-review__actions">
        {items.map((it, i) => (
          <li key={i}>
            <label className="cc-meet-review__check">
              <input
                type="checkbox"
                checked={it.completed}
                onChange={(e) => patch(i, { completed: e.target.checked })}
              />
            </label>
            <select
              value={it.owner || "both"}
              onChange={(e) => patch(i, { owner: e.target.value })}
              className="cc-meet-review__owner"
            >
              <option value="simon">Simon</option>
              <option value="perrie">Perrie</option>
              <option value="both">Both</option>
            </select>
            <Input value={it.text} onChange={(v) => patch(i, { text: v })} />
            <Input
              type="date"
              value={it.due_date || ""}
              onChange={(v) => patch(i, { due_date: v || null })}
            />
            <button
              type="button"
              className="cc-meet-review__rm"
              onClick={() => remove(i)}
              aria-label="Remove"
            >
              {Icons.x(14)}
            </button>
          </li>
        ))}
        <li>
          <button type="button" className="cc-meet-review__add-row" onClick={add}>
            {Icons.plus(14)} Add action item
          </button>
        </li>
      </ul>
    );
  }

  function CarryoverEditor({ items, status, onChange }) {
    function set(text, value) {
      onChange({ ...status, [text]: value });
    }
    return (
      <ul className="cc-meet-review__carry">
        {items.map((c) => {
          const cur = status[c.text] || "still_open";
          return (
            <li key={c.text}>
              <span className="cc-meet-review__carry-text">{c.text}</span>
              <div className="cc-tag-row">
                {[
                  { v: "resolved", l: "Resolved" },
                  { v: "still_open", l: "Still open" },
                  { v: "dropped", l: "Dropped" },
                ].map((o) => (
                  <button
                    key={o.v}
                    type="button"
                    onClick={() => set(c.text, o.v)}
                    className={`cc-tag ${cur === o.v ? "is-active" : ""}`}
                  >
                    {o.l}
                  </button>
                ))}
              </div>
            </li>
          );
        })}
      </ul>
    );
  }

  window.CC = window.CC || {};
  window.CC.Meetings = Meetings;
})();
