const { useState } = React;
// CAL // Opportunity Triage
// Compliant co-pilot: scores a pasted job + drafts a tailored proposal.
// You review and submit manually on the platform. Nothing is auto-sent.

const PLATFORMS = [
  { id: "upwork", label: "Upwork", url: "https://www.upwork.com/nx/find-work/" },
  { id: "fiverr", label: "Fiverr", url: "https://www.fiverr.com/" },
  { id: "contra", label: "Contra", url: "https://contra.com/" },
  { id: "other", label: "Other", url: "" },
];

const DEFAULT_OFFER = `I take AI-generated prototypes (Lovable, Bolt, v0, Replit, Cursor) to production, and modernize legacy WordPress sites into Next.js. Senior full-stack engineer: Next.js, React, Node, TypeScript, Cloudflare (Workers / D1 / R2), Postgres. I harden auth, fix database schemas, close security gaps, and ship reliable, deployable software. Founder of Cryptic Arts Laboratory.

Packages: Audit ($300-500, fast turnaround) / Production Hardening Sprint ($1.5k-4k) / Full build or migration ($5k+).`;

// ---- inline Heroicons (no emoji, per house style) ----
const Icon = {
  Bolt: (p) => (
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" {...p}>
      <path d="M13 2 4.5 13.5H11l-1 8.5L19.5 10H13z" />
    </svg>
  ),
  Clipboard: (p) => (
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" {...p}>
      <path d="M9 4.5h6a1.5 1.5 0 0 1 1.5 1.5v0a1.5 1.5 0 0 1-1.5 1.5H9A1.5 1.5 0 0 1 7.5 6v0A1.5 1.5 0 0 1 9 4.5Z" />
      <path d="M7.5 6H6a2 2 0 0 0-2 2v11a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-1.5" />
    </svg>
  ),
  Check: (p) => (
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" {...p}>
      <path d="m5 12.5 4.5 4.5L19 7" />
    </svg>
  ),
  ArrowUpRight: (p) => (
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" {...p}>
      <path d="M7 17 17 7M8 7h9v9" />
    </svg>
  ),
  Warning: (p) => (
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" {...p}>
      <path d="M12 9v4m0 4h.01M10.3 3.9 2.4 18a1.9 1.9 0 0 0 1.6 2.8h15.9a1.9 1.9 0 0 0 1.7-2.8L13.7 3.9a1.9 1.9 0 0 0-3.4 0Z" />
    </svg>
  ),
  Spinner: (p) => (
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" {...p}>
      <path d="M12 3a9 9 0 1 0 9 9" />
    </svg>
  ),
};

function scoreColor(s) {
  if (s >= 75) return "var(--good)";
  if (s >= 50) return "var(--mid)";
  return "var(--low)";
}

function OpportunityTriage() {
  const [offer, setOffer] = useState(DEFAULT_OFFER);
  const [showOffer, setShowOffer] = useState(false);
  const [platform, setPlatform] = useState("upwork");
  const [jobText, setJobText] = useState("");
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState("");
  const [queue, setQueue] = useState([]);
  const [copiedId, setCopiedId] = useState(null);

  async function triage() {
    const text = jobText.trim();
    if (!text || loading) return;
    setLoading(true);
    setError("");

    const prompt = `You are triaging a freelance job posting for a senior full-stack engineer. Here is the engineer's offer:

<offer>
${offer}
</offer>

Here is the job posting (from ${platform}):

<job>
${text}
</job>

Assess fit and write a proposal. Respond ONLY with valid JSON, no markdown fences, no preamble, in exactly this shape:
{
  "fitScore": <integer 0-100, how well this matches the offer>,
  "fitReason": "<one short sentence>",
  "stack": "<tech/tools mentioned, or 'unclear'>",
  "budget": "<budget signal, or 'unclear'>",
  "timeline": "<timeline signal, or 'unclear'>",
  "redFlags": ["<short flag>", ...],
  "draft": "<a tailored proposal, 90-150 words, confident senior-engineer voice, references the job's actual needs, names a concrete first step, no fluff, no greeting like 'Dear client', open with the value not 'I am'>"
}`;

    try {
      const res = await fetch("https://api.anthropic.com/v1/messages", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          model: "claude-sonnet-4-20250514",
          max_tokens: 1000,
          messages: [{ role: "user", content: prompt }],
        }),
      });
      const data = await res.json();
      const raw = (data.content || [])
        .filter((b) => b.type === "text")
        .map((b) => b.text)
        .join("\n")
        .replace(/```json|```/g, "")
        .trim();

      let parsed;
      try {
        parsed = JSON.parse(raw);
      } catch {
        parsed = { fitScore: 0, fitReason: "Could not parse model output.", stack: "—", budget: "—", timeline: "—", redFlags: [], draft: raw };
      }

      const item = {
        id: Date.now(),
        platform,
        platformUrl: PLATFORMS.find((p) => p.id === platform)?.url || "",
        snippet: text.slice(0, 140),
        ...parsed,
      };
      setQueue((q) => [item, ...q].sort((a, b) => (b.fitScore || 0) - (a.fitScore || 0)));
      setJobText("");
    } catch (e) {
      setError("Request failed. Check the connection and try again.");
    } finally {
      setLoading(false);
    }
  }

  async function copyDraft(item) {
    try {
      await navigator.clipboard.writeText(item.draft);
      setCopiedId(item.id);
      setTimeout(() => setCopiedId((c) => (c === item.id ? null : c)), 1600);
    } catch {
      setError("Copy failed — select the text manually.");
    }
  }

  return (
    <div style={styles.root}>
      <style>{css}</style>

      <header style={styles.header}>
        <div>
          <div style={styles.kicker}>CRYPTIC ARTS LABORATORY</div>
          <h1 style={styles.h1}>Opportunity Triage</h1>
        </div>
        <div style={styles.pill}>
          <Icon.Warning width={14} height={14} />
          <span>Drafts only — you review &amp; send</span>
        </div>
      </header>

      {/* Offer profile */}
      <section style={styles.panel}>
        <button style={styles.offerToggle} onClick={() => setShowOffer((s) => !s)}>
          <span style={styles.label}>Your offer profile</span>
          <span style={styles.offerHint}>{showOffer ? "hide" : "edit"}</span>
        </button>
        {showOffer ? (
          <textarea
            style={{ ...styles.textarea, minHeight: 160 }}
            value={offer}
            onChange={(e) => setOffer(e.target.value)}
          />
        ) : (
          <p style={styles.offerPreview}>{offer.split("\n")[0]}</p>
        )}
      </section>

      {/* Input */}
      <section style={styles.panel}>
        <div style={styles.platformRow}>
          {PLATFORMS.map((p) => (
            <button
              key={p.id}
              onClick={() => setPlatform(p.id)}
              style={{
                ...styles.platformBtn,
                ...(platform === p.id ? styles.platformBtnActive : {}),
              }}
            >
              {p.label}
            </button>
          ))}
        </div>
        <textarea
          style={styles.textarea}
          placeholder="Paste a job posting here — title and full description. The more detail, the sharper the draft."
          value={jobText}
          onChange={(e) => setJobText(e.target.value)}
        />
        <div style={styles.actionRow}>
          <button
            onClick={triage}
            disabled={loading || !jobText.trim()}
            style={{
              ...styles.triageBtn,
              ...(loading || !jobText.trim() ? styles.triageBtnDisabled : {}),
            }}
          >
            {loading ? <Icon.Spinner className="spin" width={16} height={16} /> : <Icon.Bolt width={16} height={16} />}
            {loading ? "Triaging…" : "Triage & draft"}
          </button>
          {error ? <span style={styles.error}>{error}</span> : null}
        </div>
      </section>

      {/* Queue */}
      <section style={styles.queueWrap}>
        <div style={styles.queueHead}>
          <span style={styles.label}>Queue</span>
          <span style={styles.queueCount}>{queue.length} ranked by fit</span>
        </div>

        {queue.length === 0 ? (
          <div style={styles.empty}>Triaged opportunities land here, highest-fit first.</div>
        ) : (
          queue.map((item) => (
            <article key={item.id} style={styles.card}>
              <div style={styles.cardTop}>
                <div style={{ ...styles.scoreBadge, color: scoreColor(item.fitScore), borderColor: scoreColor(item.fitScore) }}>
                  <span style={styles.scoreNum}>{item.fitScore}</span>
                  <span style={styles.scoreLabel}>fit</span>
                </div>
                <div style={{ flex: 1 }}>
                  <div style={styles.cardMeta}>
                    <span style={styles.platformTag}>{item.platform}</span>
                    <span style={styles.fitReason}>{item.fitReason}</span>
                  </div>
                  <div style={styles.chips}>
                    {item.stack && item.stack !== "unclear" ? <span style={styles.chip}>stack · {item.stack}</span> : null}
                    {item.budget && item.budget !== "unclear" ? <span style={styles.chip}>budget · {item.budget}</span> : null}
                    {item.timeline && item.timeline !== "unclear" ? <span style={styles.chip}>timeline · {item.timeline}</span> : null}
                  </div>
                </div>
              </div>

              {item.redFlags && item.redFlags.length ? (
                <div style={styles.flags}>
                  <Icon.Warning width={13} height={13} style={{ flexShrink: 0, marginTop: 1 }} />
                  <span>{item.redFlags.join(" · ")}</span>
                </div>
              ) : null}

              <div style={styles.draftBox}>
                <p style={styles.draftText}>{item.draft}</p>
              </div>

              <div style={styles.cardActions}>
                <button style={styles.copyBtn} onClick={() => copyDraft(item)}>
                  {copiedId === item.id ? <Icon.Check width={15} height={15} /> : <Icon.Clipboard width={15} height={15} />}
                  {copiedId === item.id ? "Copied" : "Copy draft"}
                </button>
                {item.platformUrl ? (
                  <a style={styles.openBtn} href={item.platformUrl} target="_blank" rel="noreferrer">
                    Open {item.platform} <Icon.ArrowUpRight width={14} height={14} />
                  </a>
                ) : null}
              </div>
            </article>
          ))
        )}
      </section>

      <footer style={styles.footer}>
        Review every draft before sending. Submission stays manual and human — that is what keeps the account safe and what actually wins the work.
      </footer>
    </div>
  );
}

const css = `
@import url('https://fonts.googleapis.com/css2?family=Fraunces:opsz,wght@9..144,400;9..144,600&family=Hanken+Grotesk:wght@400;500;600&family=JetBrains+Mono:wght@400;500&display=swap');
.spin { animation: spin 0.8s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }
textarea::placeholder { color: #6b6862; }
* { box-sizing: border-box; }
`;

const styles = {
  root: {
    "--bg": "#0b0b0d",
    "--panel": "#141416",
    "--panel2": "#1b1b1e",
    "--line": "#2a2a2e",
    "--text": "#e9e4d8",
    "--muted": "#8b877d",
    "--accent": "#e0a83d",
    "--good": "#8fc46b",
    "--mid": "#e0a83d",
    "--low": "#c76b5a",
    background: "var(--bg)",
    color: "var(--text)",
    fontFamily: "'Hanken Grotesk', sans-serif",
    minHeight: "100%",
    padding: "28px clamp(16px, 4vw, 40px) 48px",
    maxWidth: 860,
    margin: "0 auto",
    lineHeight: 1.5,
  },
  header: { display: "flex", justifyContent: "space-between", alignItems: "flex-start", gap: 16, marginBottom: 26, flexWrap: "wrap" },
  kicker: { fontFamily: "'JetBrains Mono', monospace", fontSize: 11, letterSpacing: "0.22em", color: "var(--accent)", marginBottom: 6 },
  h1: { fontFamily: "'Fraunces', serif", fontWeight: 600, fontSize: "clamp(28px, 6vw, 40px)", margin: 0, letterSpacing: "-0.01em" },
  pill: { display: "flex", alignItems: "center", gap: 7, fontSize: 12, color: "var(--muted)", border: "1px solid var(--line)", borderRadius: 999, padding: "6px 12px", fontFamily: "'JetBrains Mono', monospace" },
  panel: { background: "var(--panel)", border: "1px solid var(--line)", borderRadius: 14, padding: 18, marginBottom: 16 },
  offerToggle: { width: "100%", display: "flex", justifyContent: "space-between", alignItems: "center", background: "none", border: "none", color: "var(--text)", cursor: "pointer", padding: 0 },
  label: { fontFamily: "'JetBrains Mono', monospace", fontSize: 11, letterSpacing: "0.18em", textTransform: "uppercase", color: "var(--muted)" },
  offerHint: { fontFamily: "'JetBrains Mono', monospace", fontSize: 11, color: "var(--accent)" },
  offerPreview: { margin: "10px 0 0", fontSize: 14, color: "var(--text)" },
  platformRow: { display: "flex", gap: 8, marginBottom: 14, flexWrap: "wrap" },
  platformBtn: { fontFamily: "'JetBrains Mono', monospace", fontSize: 12, background: "var(--panel2)", color: "var(--muted)", border: "1px solid var(--line)", borderRadius: 8, padding: "7px 14px", cursor: "pointer" },
  platformBtnActive: { color: "var(--bg)", background: "var(--accent)", borderColor: "var(--accent)", fontWeight: 500 },
  textarea: { width: "100%", minHeight: 130, background: "var(--panel2)", color: "var(--text)", border: "1px solid var(--line)", borderRadius: 10, padding: 14, fontSize: 14, fontFamily: "'Hanken Grotesk', sans-serif", resize: "vertical", outline: "none", lineHeight: 1.55 },
  actionRow: { display: "flex", alignItems: "center", gap: 14, marginTop: 14 },
  triageBtn: { display: "inline-flex", alignItems: "center", gap: 8, background: "var(--accent)", color: "var(--bg)", border: "none", borderRadius: 9, padding: "11px 20px", fontSize: 14, fontWeight: 600, cursor: "pointer", fontFamily: "'Hanken Grotesk', sans-serif" },
  triageBtnDisabled: { opacity: 0.4, cursor: "not-allowed" },
  error: { color: "var(--low)", fontSize: 13 },
  queueWrap: { marginTop: 28 },
  queueHead: { display: "flex", justifyContent: "space-between", alignItems: "baseline", marginBottom: 14 },
  queueCount: { fontFamily: "'JetBrains Mono', monospace", fontSize: 11, color: "var(--muted)" },
  empty: { border: "1px dashed var(--line)", borderRadius: 12, padding: "32px 20px", textAlign: "center", color: "var(--muted)", fontSize: 14 },
  card: { background: "var(--panel)", border: "1px solid var(--line)", borderRadius: 14, padding: 18, marginBottom: 14 },
  cardTop: { display: "flex", gap: 16, alignItems: "flex-start" },
  scoreBadge: { display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", width: 58, height: 58, border: "1.5px solid", borderRadius: 12, flexShrink: 0 },
  scoreNum: { fontFamily: "'Fraunces', serif", fontSize: 24, fontWeight: 600, lineHeight: 1 },
  scoreLabel: { fontFamily: "'JetBrains Mono', monospace", fontSize: 9, letterSpacing: "0.15em", textTransform: "uppercase", marginTop: 3, opacity: 0.8 },
  cardMeta: { display: "flex", alignItems: "center", gap: 10, flexWrap: "wrap", marginBottom: 8 },
  platformTag: { fontFamily: "'JetBrains Mono', monospace", fontSize: 10, letterSpacing: "0.12em", textTransform: "uppercase", color: "var(--accent)", border: "1px solid var(--line)", borderRadius: 5, padding: "2px 7px" },
  fitReason: { fontSize: 13.5, color: "var(--text)" },
  chips: { display: "flex", gap: 7, flexWrap: "wrap" },
  chip: { fontFamily: "'JetBrains Mono', monospace", fontSize: 11, color: "var(--muted)", background: "var(--panel2)", borderRadius: 6, padding: "3px 8px" },
  flags: { display: "flex", alignItems: "flex-start", gap: 7, marginTop: 12, color: "var(--low)", fontSize: 12.5, fontFamily: "'JetBrains Mono', monospace" },
  draftBox: { marginTop: 14, background: "var(--panel2)", border: "1px solid var(--line)", borderRadius: 10, padding: 14 },
  draftText: { margin: 0, fontSize: 14, color: "var(--text)", whiteSpace: "pre-wrap", lineHeight: 1.6 },
  cardActions: { display: "flex", gap: 10, marginTop: 14, flexWrap: "wrap" },
  copyBtn: { display: "inline-flex", alignItems: "center", gap: 7, background: "var(--accent)", color: "var(--bg)", border: "none", borderRadius: 8, padding: "9px 15px", fontSize: 13, fontWeight: 600, cursor: "pointer", fontFamily: "'Hanken Grotesk', sans-serif" },
  openBtn: { display: "inline-flex", alignItems: "center", gap: 6, background: "none", color: "var(--text)", border: "1px solid var(--line)", borderRadius: 8, padding: "9px 15px", fontSize: 13, cursor: "pointer", textDecoration: "none", fontFamily: "'Hanken Grotesk', sans-serif" },
  footer: { marginTop: 30, paddingTop: 18, borderTop: "1px solid var(--line)", fontSize: 12.5, color: "var(--muted)", lineHeight: 1.6 },
};


ReactDOM.createRoot(document.getElementById("root")).render(<OpportunityTriage />);
