import { useEffect, useRef, useState } from "react";
import type { ChatMessage, JobExtract, MatchResult, PlanResponse } from "../../shared/types";
import type { GeneratedResume } from "../App";
import { ApiRequestError, compilePdf, post } from "../api";

interface WorkspaceProps {
  jd: JobExtract;
  messages: ChatMessage[];
  onMessagesChange: (messages: ChatMessage[]) => void;
  onBack: () => void;
  onGenerated: (result: GeneratedResume) => void;
}

export function Workspace({ jd, messages, onMessagesChange, onBack, onGenerated }: WorkspaceProps) {
  const [match, setMatch] = useState<MatchResult | null>(null);
  const [matchError, setMatchError] = useState("");
  const [draft, setDraft] = useState("");
  const [chatBusy, setChatBusy] = useState(false);
  const [genStep, setGenStep] = useState("");
  const [genError, setGenError] = useState("");
  const chatEndRef = useRef<HTMLDivElement | null>(null);

  useEffect(() => {
    let cancelled = false;
    post<MatchResult>("/api/match", { text: jd.text })
      .then((m) => {
        if (!cancelled) setMatch(m);
      })
      .catch((err: unknown) => {
        if (!cancelled) setMatchError(err instanceof Error ? err.message : String(err));
      });
    return () => {
      cancelled = true;
    };
  }, [jd.text]);

  useEffect(() => {
    chatEndRef.current?.scrollIntoView({ behavior: "smooth" });
  }, [messages, chatBusy]);

  async function sendChat(): Promise<void> {
    const content = draft.trim();
    if (content.length === 0 || chatBusy || !match) return;
    const next: ChatMessage[] = [...messages, { role: "user", content }];
    onMessagesChange(next);
    setDraft("");
    setChatBusy(true);
    try {
      const { reply } = await post<{ reply: string }>("/api/chat", { jd, match, messages: next });
      onMessagesChange([...next, { role: "assistant", content: reply }]);
    } catch (err) {
      const message = err instanceof Error ? err.message : String(err);
      onMessagesChange([...next, { role: "assistant", content: `(error) ${message}` }]);
    } finally {
      setChatBusy(false);
    }
  }

  async function generate(): Promise<void> {
    if (!match || genStep) return;
    setGenError("");
    try {
      setGenStep("Planning selection with AI…");
      const planRes = await post<PlanResponse>("/api/plan", { jd, match, chat: messages });
      setGenStep("Rendering LaTeX…");
      const { latex } = await post<{ latex: string }>("/api/latex", { plan: planRes.plan });
      setGenStep("Compiling PDF…");
      const blob = await compilePdf(latex);
      onGenerated({
        plan: planRes.plan,
        source: planRes.source,
        note: planRes.note,
        latex,
        pdfUrl: URL.createObjectURL(blob),
      });
    } catch (err) {
      if (err instanceof ApiRequestError && err.log) {
        setGenError(`${err.message}\n\n${err.log}`);
      } else {
        setGenError(err instanceof Error ? err.message : String(err));
      }
      setGenStep("");
    }
  }

  const matchedItems = match?.items.filter((i) => i.score > 0) ?? [];

  return (
    <div className="workspace">
      <header className="topbar">
        <button type="button" className="btn ghost" onClick={onBack}>
          ← New posting
        </button>
        <div className="topbar-title">
          <strong>{jd.title}</strong>
          <span className="muted">
            {jd.source === "manual" ? "pasted manually" : `${jd.url} · extracted via ${jd.source}`}
          </span>
        </div>
        <button type="button" className="btn primary" onClick={() => void generate()} disabled={!match || genStep !== ""}>
          {genStep !== "" ? genStep : "Generate PDF"}
        </button>
      </header>

      {genError && <pre className="error banner">{genError}</pre>}

      <div className="workspace-grid">
        <section className="panel">
          <h2>Job Posting</h2>
          <pre className="jd-text">{jd.text}</pre>
        </section>

        <section className="panel">
          <h2>
            Matched Material
            {match && <span className="muted"> — {match.skills.length} skills hit</span>}
          </h2>
          {matchError && <div className="error">{matchError}</div>}
          {!match && !matchError && <div className="loading">Matching against the corpus…</div>}
          {match && (
            <>
              <div className="chips">
                {match.skills.map((s) => (
                  <span key={s.name} className={`chip ${s.category}`} title={s.category}>
                    {s.name} <em>×{s.hits}</em>
                  </span>
                ))}
                {match.skills.length === 0 && <span className="muted">No skill overlap found.</span>}
              </div>
              <div className="items">
                {matchedItems.map((item) => (
                  <article key={`${item.type}:${item.slug}`} className="item-card">
                    <header>
                      <span className={`badge ${item.type}`}>{item.type}</span>
                      <strong>{item.title}</strong>
                      <span className="muted">
                        {item.company ? `${item.company} · ` : ""}
                        {item.dates} · score {item.score}
                      </span>
                    </header>
                    <div className="mini-chips">
                      {item.matchedSkills.map((s) => (
                        <span key={s} className="chip mini">
                          {s}
                        </span>
                      ))}
                    </div>
                    <ul>
                      {item.bullets.slice(0, 3).map((b) => (
                        <li key={b.slice(0, 40)}>{b}</li>
                      ))}
                    </ul>
                  </article>
                ))}
              </div>
            </>
          )}
        </section>
      </div>

      <section className="chat panel">
        <h2>Refine with the agent</h2>
        <div className="chat-log">
          {messages.length === 0 && (
            <div className="muted chat-empty">
              Ask the agent to emphasize certain skills, pick different projects, or adjust the
              headline — the conversation is folded into the plan when you hit Generate.
            </div>
          )}
          {messages.map((m, i) => (
            <div key={`${i}-${m.content.slice(0, 20)}`} className={`msg ${m.role}`}>
              {m.content}
            </div>
          ))}
          {chatBusy && <div className="msg assistant pending">…</div>}
          <div ref={chatEndRef} />
        </div>
        <form
          className="chat-form"
          onSubmit={(e) => {
            e.preventDefault();
            void sendChat();
          }}
        >
          <input
            value={draft}
            onChange={(e) => setDraft(e.target.value)}
            placeholder={match ? "e.g. Lead with the cryptography work, skip consumer apps" : "Waiting for match…"}
            disabled={!match}
          />
          <button type="submit" className="btn" disabled={!match || chatBusy || draft.trim().length === 0}>
            Send
          </button>
        </form>
      </section>
    </div>
  );
}
