// ============== jobs board ==============

function Jobs({ go, focusId }) {
  const { CHAIN_FILTERS, TYPE_FILTERS, LEVEL_FILTERS, REMOTE_FILTERS, useRoles } = window.W3J;
  const { roles: ROLES, loading, source } = useRoles();
  const [q, setQ] = React.useState("");
  const [chain, setChain] = React.useState(new Set());
  const [cat, setCat] = React.useState(new Set());
  const [level, setLevel] = React.useState(new Set());
  const [remote, setRemote] = React.useState(new Set());
  const [minComp, setMinComp] = React.useState(0);
  const [sort, setSort] = React.useState("recent");
  const [active, setActive] = React.useState(null);

  React.useEffect(() => {
    if (focusId) {
      const r = ROLES.find((x) => x.id === focusId);
      if (r) setActive(r);
    }
  }, [focusId, ROLES]);

  const toggle = (set, setSet, val) => {
    const next = new Set(set);
    if (next.has(val)) next.delete(val); else next.add(val);
    setSet(next);
  };

  const filtered = React.useMemo(() => {
    const remoteMatch = (r) => {
      if (remote.size === 0) return true;
      return [...remote].some((rk) => r.remote.toLowerCase().startsWith(rk.toLowerCase()));
    };
    let list = ROLES.filter((r) => {
      if (q) {
        const hay = (r.title + " " + r.company + " " + r.stack.join(" ") + " " + r.chain + " " + r.cat).toLowerCase();
        if (!hay.includes(q.toLowerCase())) return false;
      }
      if (chain.size && !chain.has(r.chain)) return false;
      if (cat.size && !cat.has(r.cat)) return false;
      if (level.size && !level.has(r.level)) return false;
      if (!remoteMatch(r)) return false;
      if (r.min < minComp) return false;
      return true;
    });
    if (sort === "recent") list = list.sort((a, b) => a.posted - b.posted);
    if (sort === "comp") list = list.sort((a, b) => b.max - a.max);
    if (sort === "title") list = list.sort((a, b) => a.title.localeCompare(b.title));
    return list;
  }, [q, chain, cat, level, remote, minComp, sort, ROLES]);

  const counts = React.useMemo(() => {
    const c = (key) => Object.fromEntries(
      [...new Set(ROLES.map((r) => r[key]))].map((v) => [v, ROLES.filter((r) => r[key] === v).length])
    );
    return { chain: c("chain"), cat: c("cat"), level: c("level") };
  }, [ROLES]);

  const clearAll = () => {
    setQ(""); setChain(new Set()); setCat(new Set()); setLevel(new Set()); setRemote(new Set()); setMinComp(0);
  };

  const totalActive = chain.size + cat.size + level.size + remote.size + (q ? 1 : 0) + (minComp > 0 ? 1 : 0);

  return (
    <main>
      <section className="page-hero">
        <div className="shell">
          <Eyebrow>The job board · {ROLES.length} live roles{source === "mock" && " (preview)"}</Eyebrow>
          <h1>Open <em>roles.</em></h1>
          <p className="lede" style={{ marginTop: 28, maxWidth: 640 }}>
            Every role here is actively retained by Web3JOE. Companies are anonymized in public listings,
            full briefs are sent to qualified candidates after a short call.
          </p>
        </div>
      </section>

      <section>
        <div className="shell">
          <div className="jb-toolbar">
            <div className="jb-search">
              <Icon.Search />
              <input placeholder="Search roles, stacks, ecosystems…" value={q} onChange={(e) => setQ(e.target.value)} />
              {q && <button onClick={() => setQ("")} style={{ color: "var(--fg-dim)", padding: 4 }}><Icon.Close size={14} /></button>}
            </div>
            <div className="jb-count">{filtered.length} / {ROLES.length} roles</div>
            <div className="jb-sort">
              <span>Sort</span>
              <select value={sort} onChange={(e) => setSort(e.target.value)}>
                <option value="recent">Most recent</option>
                <option value="comp">Highest comp</option>
                <option value="title">A → Z</option>
              </select>
            </div>
          </div>
        </div>

        <div className="shell">
          <div className="jb-layout">
            <aside className="jb-filters">
              <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 24 }}>
                <div className="eyebrow">Filters {totalActive > 0 && <span style={{ color: "var(--accent)" }}>· {totalActive}</span>}</div>
                {totalActive > 0 && <span className="jb-clear" onClick={clearAll}>Clear all</span>}
              </div>
              <FilterGroup title="Ecosystem" opts={CHAIN_FILTERS} active={chain} onToggle={(v) => toggle(chain, setChain, v)} counts={counts.chain} />
              <FilterGroup title="Specialization" opts={TYPE_FILTERS} active={cat} onToggle={(v) => toggle(cat, setCat, v)} counts={counts.cat} />
              <FilterGroup title="Seniority" opts={LEVEL_FILTERS} active={level} onToggle={(v) => toggle(level, setLevel, v)} counts={counts.level} />
              <FilterGroup title="Location" opts={REMOTE_FILTERS} active={remote} onToggle={(v) => toggle(remote, setRemote, v)} />
              <div className="jb-filter-group">
                <h6>Min total comp</h6>
                <div className="jb-range">
                  <input type="range" min="0" max="400" step="20" value={minComp} onChange={(e) => setMinComp(Number(e.target.value))} />
                </div>
                <div style={{ marginTop: 8, fontFamily: "var(--mono)", fontSize: 12, color: "var(--fg)" }}>${minComp}k+</div>
              </div>
            </aside>

            <div className="jb-results">
              {loading ? (
                <div className="jb-empty"><div className="h3">Loading…</div></div>
              ) : filtered.length === 0 ? (
                <div className="jb-empty">
                  <div className="h3">No matches.</div>
                  <p>Try widening your filters — or <span className="jb-clear" onClick={clearAll}>clear all</span>.</p>
                </div>
              ) : (
                <div className="role-list">
                  {filtered.map((r) => (
                    <div className="role-card" key={r.id} onClick={() => setActive(r)}>
                      <span className="rid">{r.id}</span>
                      <div>
                        <div className="rtitle">{r.title}</div>
                        <div className="rcompany">{r.company} · {r.remote} · posted {r.posted}d ago</div>
                      </div>
                      <div className="rmeta">
                        <span className="chip">{r.chain}</span>
                        {r.stack.slice(0, 2).map((s) => <span className="chip" key={s}>{s}</span>)}
                      </div>
                      <div className="rcomp"><span className="ccy">$</span>{r.min}–{r.max}k</div>
                      <div className="rarrow"><Icon.Arrow size={12} /></div>
                    </div>
                  ))}
                </div>
              )}
            </div>
          </div>
        </div>
      </section>

      <JobDrawer role={active} onClose={() => setActive(null)} go={go} />
    </main>
  );
}

function FilterGroup({ title, opts, active, onToggle, counts }) {
  return (
    <div className="jb-filter-group">
      <h6>{title}</h6>
      {opts.map((c) => (
        <div key={c} className={`jb-check ${active.has(c) ? "is-on" : ""}`} onClick={() => onToggle(c)}>
          <span className="box" />
          <span>{c}</span>
          {counts && <span className="count">{counts[c] || 0}</span>}
        </div>
      ))}
    </div>
  );
}

function JobDrawer({ role, onClose, go }) {
  const { user } = useAuth();
  const [applied, setApplied] = React.useState(false);
  const [applying, setApplying] = React.useState(false);
  const [err, setErr] = React.useState("");
  const [showApplyForm, setShowApplyForm] = React.useState(false);
  const [profile, setProfile] = React.useState(null);
  const [form, setForm] = React.useState(blankForm());
  const [answers, setAnswers] = React.useState({});
  const [resumeMode, setResumeMode] = React.useState("profile"); // "profile" | "upload"
  const [uploadedKey, setUploadedKey] = React.useState(null);
  const [uploading, setUploading] = React.useState(false);
  const fileInputRef = React.useRef(null);

  React.useEffect(() => {
    const onKey = (e) => { if (e.key === "Escape") onClose(); };
    if (role) window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [role]);

  React.useEffect(() => {
    setApplied(false); setShowApplyForm(false); setErr(""); setAnswers({});
    setResumeMode("profile"); setUploadedKey(null);
  }, [role?.id]);

  React.useEffect(() => {
    if (!showApplyForm || !user || user.role !== "candidate") return;
    window.W3J_API.apiFetch("/candidates/me").then((p) => {
      setProfile(p);
      setForm({
        full_name: p.full_name || "",
        email: user.email || "",
        linkedin_url: p.linkedin_url || "",
        twitter_url: p.twitter_url || "",
        location: p.location || "",
        expected_comp: "",
      });
      setResumeMode(p.resume_key ? "profile" : "upload");
    }).catch(() => {});
  }, [showApplyForm, user]);

  const setField = (k) => (e) => setForm((f) => ({ ...f, [k]: e.target.value }));
  const setAnswer = (qid) => (e) => setAnswers((a) => ({ ...a, [qid]: e.target.value }));

  const uploadResume = async (file) => {
    if (!file) return;
    setErr(""); setUploading(true);
    try {
      const fd = new FormData();
      fd.append("file", file);
      const res = await window.W3J_API.apiFetch("/uploads/application-resume", {
        method: "POST", body: fd, isForm: true,
      });
      setUploadedKey(res.resume_key);
    } catch (ex) {
      setErr(ex.message || "upload failed");
    } finally {
      setUploading(false);
    }
  };

  const apply = async (e) => {
    if (e) e.preventDefault();
    setErr(""); setApplying(true);
    try {
      if (!role?.uuid) throw new Error("This is a preview role. Roles will be live once the recruiter creates them.");
      const resume_key =
        resumeMode === "upload" ? uploadedKey
        : (profile?.resume_key || null);
      if (!resume_key) {
        throw new Error("Please attach a resume — upload here or via your dashboard.");
      }
      const body = {
        role_id: role.uuid,
        full_name: form.full_name,
        email: form.email,
        linkedin_url: form.linkedin_url,
        twitter_url: form.twitter_url || null,
        location: form.location,
        expected_comp: form.expected_comp || null,
        resume_key,
        answers,
      };
      await window.W3J_API.apiFetch("/applications", { method: "POST", body });
      setApplied(true);
    } catch (ex) {
      if (ex.status === 409) setApplied(true);
      else setErr(ex.message);
    } finally {
      setApplying(false);
    }
  };

  const questions = role?.questions || [];

  return (
    <>
      <div className={`jb-drawer-bg ${role ? "is-open" : ""}`} onClick={onClose} />
      <aside className={`jb-drawer ${role ? "is-open" : ""}`} role="dialog" aria-hidden={!role}>
        {role && (
          <>
            <div className="jb-drawer-head">
              <div>
                <div className="company">{role.id} · {role.company}</div>
                <h2>{role.title}</h2>
                <div style={{ display: "flex", gap: 6, flexWrap: "wrap", marginTop: 12 }}>
                  {role.chain && <span className="chip chip--solid">{role.chain}</span>}
                  {role.stack.map((s) => <span className="chip" key={s}>{s}</span>)}
                </div>
              </div>
              <div style={{ display: "flex", gap: 6 }}>
                <a href={`#roles/${role.id}`} target="_blank" rel="noopener noreferrer"
                   className="btn btn--ghost" style={{ padding: "8px 10px" }} title="Open full role page">
                  <Icon.ArrowUR />
                </a>
                <button onClick={onClose} className="btn btn--ghost" style={{ padding: "8px 10px" }}>
                  <Icon.Close />
                </button>
              </div>
            </div>

            <div className="jb-drawer-body">
              <div className="jb-drawer-meta">
                <div className="jb-meta-row"><div className="label">Total comp</div><div className="value">${role.min}–${role.max}k + tokens</div></div>
                <div className="jb-meta-row"><div className="label">Location</div><div className="value">{role.remote}</div></div>
                <div className="jb-meta-row"><div className="label">Seniority</div><div className="value">{role.level}</div></div>
                <div className="jb-meta-row"><div className="label">Type</div><div className="value">{role.type}</div></div>
              </div>

              {role.description && (<><h4>About the role</h4><p style={{ whiteSpace: "pre-wrap" }}>{role.description}</p></>)}

              {role.requirements && role.requirements.length > 0 ? (
                <><h4>What we're looking for</h4>
                <ul>{role.requirements.map((s, i) => <li key={i}>{s}</li>)}</ul></>
              ) : (
                <><h4>About the company</h4>
                <p>A {role.company.toLowerCase()} operating at the frontier of {role.cat.toLowerCase()}. Backed by tier-1 funds, profitable, and shipping product to mainnet weekly. Full brief shared with shortlisted candidates after intro call.</p></>
              )}

              {role.offer && role.offer.length > 0 ? (
                <><h4>What's on offer</h4>
                <ul>{role.offer.map((s, i) => <li key={i}>{s}</li>)}</ul></>
              ) : (
                <><h4>What's on offer</h4>
                <ul>
                  <li>Base ${role.min}–${role.max}k + meaningful token allocation.</li>
                  <li>4-year vesting with 1-year cliff. Acceleration clauses negotiable.</li>
                  <li>Top-tier health, vision, dental coverage globally.</li>
                  <li>Annual onsites in Lisbon, NYC, Singapore, Dubai.</li>
                </ul></>
              )}

              {showApplyForm && !applied && (
                <form className="apply-form" onSubmit={apply} id={`apply-${role.id}`}>
                  <h4 className="form-h">Application</h4>
                  <div className="field-row">
                    <label className="field"><span className="field-label">Full name *</span>
                      <input value={form.full_name} onChange={setField("full_name")} required maxLength={160} /></label>
                    <label className="field"><span className="field-label">Email *</span>
                      <input type="email" value={form.email} onChange={setField("email")} required /></label>
                  </div>
                  <div className="field-row">
                    <label className="field"><span className="field-label">LinkedIn *</span>
                      <input type="url" value={form.linkedin_url} onChange={setField("linkedin_url")} required placeholder="https://linkedin.com/in/…" /></label>
                    <label className="field"><span className="field-label">X / Twitter</span>
                      <input type="url" value={form.twitter_url} onChange={setField("twitter_url")} placeholder="https://x.com/…" /></label>
                  </div>
                  <div className="field-row">
                    <label className="field"><span className="field-label">Location *</span>
                      <input value={form.location} onChange={setField("location")} required placeholder="City, country or 'Remote'" /></label>
                    <label className="field"><span className="field-label">Expected comp</span>
                      <input value={form.expected_comp} onChange={setField("expected_comp")} placeholder={`Role pays $${role.min}–${role.max}k`} /></label>
                  </div>

                  <div className="field">
                    <span className="field-label">Resume *</span>
                    <div className="resume-options">
                      {profile?.resume_key && (
                        <label className="resume-opt">
                          <input type="radio" name={`r-${role.id}`} checked={resumeMode === "profile"} onChange={() => setResumeMode("profile")} />
                          Use the resume from my profile
                        </label>
                      )}
                      <label className="resume-opt">
                        <input type="radio" name={`r-${role.id}`} checked={resumeMode === "upload"} onChange={() => setResumeMode("upload")} />
                        Upload a different file for this role
                      </label>
                      {resumeMode === "upload" && (
                        <div className="resume-upload">
                          <input ref={fileInputRef} type="file"
                            accept=".pdf,.doc,.docx,application/pdf,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document"
                            onChange={(e) => uploadResume(e.target.files?.[0])} />
                          {uploading && <span className="mono small">Uploading…</span>}
                          {uploadedKey && <span className="mono small">✓ Uploaded</span>}
                        </div>
                      )}
                    </div>
                  </div>

                  {questions.length > 0 && (
                    <div className="custom-q-block">
                      <h5 className="form-h" style={{ marginTop: 8 }}>Additional questions</h5>
                      {questions.map((q) => (
                        <label key={q.id} className="field">
                          <span className="field-label">{q.label}{q.required ? " *" : ""}</span>
                          {q.type === "textarea" ? (
                            <textarea rows={4} value={answers[q.id] || ""} onChange={setAnswer(q.id)} required={q.required} />
                          ) : (
                            <input type={q.type === "url" ? "url" : q.type === "number" ? "number" : "text"}
                              value={answers[q.id] || ""} onChange={setAnswer(q.id)} required={q.required} />
                          )}
                        </label>
                      ))}
                    </div>
                  )}

                  {err && <div className="form-error">{err}</div>}
                </form>
              )}
            </div>

            <div className="jb-drawer-foot">
              <span className="mono" style={{ fontSize: 11, color: "var(--fg-faint)", letterSpacing: "0.06em" }}>
                APPLICATIONS REVIEWED WITHIN 48H
              </span>
              {applied ? (
                <Btn kind="ghost" arrow={false}>Applied ✓</Btn>
              ) : !user ? (
                <Btn kind="primary" arrow={true} onClick={() => go("login")}>Sign in to apply</Btn>
              ) : user.role !== "candidate" ? (
                <Btn kind="ghost" arrow={false}>Recruiter view</Btn>
              ) : !showApplyForm ? (
                <Btn kind="primary" onClick={() => setShowApplyForm(true)}>Apply for this role</Btn>
              ) : (
                <button type="submit" form={`apply-${role.id}`} className="btn btn--primary" disabled={applying}>
                  {applying ? "…" : "Submit application"} {!applying && <Icon.Arrow />}
                </button>
              )}
            </div>
          </>
        )}
      </aside>
    </>
  );
}

function blankForm() {
  return {
    full_name: "", email: "", linkedin_url: "", twitter_url: "",
    location: "", expected_comp: "",
  };
}

window.Jobs = Jobs;
