// Just Travel — "Todas as vagas" (all jobs listing) page app. Tag: VG
// Loaded as <script type="text/babel"> AFTER React UMD, landing-sections.jsx,
// landing-footer.jsx and jobs-data.js. Shares ONE global scope with the other
// babel scripts, so:
//   - no import/export/require
//   - no top-level `const { useState } = React` (would collide) — use React.* directly
//   - every top-level name is unique and prefixed VG_ / VGApp
// Openings come from window.InHire (jobs-data.js), fetched live from the ATS.
// Nothing about a vacancy is written in this file: no titles, no locations, no
// descriptions, no counts. If InHire does not return it, this page does not
// show it.

/* jobs-data.js defines window.InHire. If it did not load, or an older copy of
   it did, referencing the global directly throws while this module is being
   evaluated and nothing renders: the whole page goes blank over one broken
   link. This stand-in keeps the page up and reports the failure where the
   openings would be. */
const VG_IH = window.InHire || {
  SITE: "https://justtravel.inhire.app",
  TALENT_POOL:
    "https://justtravel.inhire.app/vagas/6ca61330-4c82-4579-811f-9a4e5ba5b377/banco-de-talentos-or-todas-as-areas-or-just-travel",
  jobDetail: () => Promise.reject(new Error("módulo não carregado")),
  useJobs: () => ({ status: "error", jobs: [], error: "o módulo de vagas não carregou" }),
  matchQuery: () => true,
};

/* The filter chips used to be a hand-written department list that InHire has no
   field for. They are rebuilt from the work model the API does return, and only
   the values actually present show up. */
const VG_WORKPLACE_ORDER = ["Remoto", "Híbrido", "Presencial"];

function VG_chips(jobs) {
  const present = VG_WORKPLACE_ORDER.filter((w) => jobs.some((j) => j.workplace === w));
  return present.length > 1 ? ["Todas"].concat(present) : [];
}

/* The chip is this page's own filter; the query is not. It arrives from the
   careers hero, whose autocomplete has already answered it, so the term is
   matched by the shared matcher in jobs-data.js rather than by a copy of the
   rule here: the two used to differ on accents, which meant a dropdown hit for
   "sao paulo" could land on an empty listing. */
function VG_matches(job, chip, query) {
  const okChip = !chip || chip === "Todas" || job.workplace === chip;
  return okChip && VG_IH.matchQuery(job, query);
}

/* ------------------------------------------------------------ hero */
function VG_Hero({ query, setQuery }) {
  return (
    <section className="vg-hero">
      <div className="container">
        <div className="vg-hero__inner">
          <a className="vg-back" href="Trabalhe-Conosco.html">
            <SIcon name="arrowRight" size={16} />
            Voltar para Trabalhe conosco
          </a>
          <span className="eyebrow">Vagas abertas</span>
          <h1 className="vg-hero__title">Todas as vagas na Just Travel</h1>
          <p className="vg-hero__sub">
            Encontre a oportunidade certa para você. Busque pelo cargo, pela cidade ou
            pelo modelo de trabalho e venha construir a travel tech das agências.
          </p>
          <div className="vg-search">
            <span className="vg-search__ic"><SIcon name="search" /></span>
            <input
              type="text"
              value={query}
              onChange={(e) => setQuery(e.target.value)}
              placeholder="Buscar por cargo ou cidade"
              aria-label="Buscar vagas" />
          </div>
        </div>
      </div>
    </section>
  );
}

/* ------------------------------------------------------------ job row

   This is the full listing rather than a preview, so each row can open the
   description InHire holds. The description is fetched per opening the first
   time a row is expanded (the list endpoint does not carry it) and rendered as
   plain-text blocks, never as markup: see IH_describe in jobs-data.js.

   Applying still happens in InHire. The row explains the opening; the button
   hands the candidate to the ATS, which owns the form, the CV upload and the
   LGPD notice. */
function VG_JobRow({ job, open, onToggle }) {
  const detId = `vaga-${job.id}`;
  const [detail, setDetail] = React.useState(null);
  const [failed, setFailed] = React.useState(false);

  React.useEffect(() => {
    if (!open || detail || failed) return;
    let alive = true;
    VG_IH.jobDetail(job.id).then(
      (d) => { if (alive) setDetail(d); },
      () => { if (alive) setFailed(true); }
    );
    return () => { alive = false; };
  }, [open]);

  return (
    <div className="car-job-item">
      <button
        type="button"
        className="car-job"
        aria-expanded={open}
        aria-controls={detId}
        onClick={onToggle}>
        <div className="car-job__main">
          <div className="car-job__title">{job.title}</div>
          <div className="car-job__meta">
            <span>{job.location}</span>
            {detail && detail.contracts.length > 0 &&
            <>
              <span className="car-job__dot">·</span>
              <span>{detail.contracts.join(", ")}</span>
            </>}
          </div>
        </div>
        <span className={`car-tag is-${job.tag}`}>{job.workplace}</span>
        <span className="car-job__go" aria-hidden="true">
          <SIcon name="arrowRight" size={20} />
        </span>
      </button>

      <div className="car-job__det" id={detId} hidden={!open}>
        <div className="car-job__body">
          {!detail && !failed &&
            <p className="car-job__desc">Carregando a descrição.</p>}

          {failed &&
            <p className="car-job__desc">
              Não foi possível carregar a descrição agora. Ela está completa na página
              da vaga.
            </p>}

          {detail && detail.blocks.map((b, i) => (
            b.type === "item"
              ? <p className="car-job__desc car-job__desc--item" key={i}>{b.text}</p>
              : b.type === "head"
                ? <h3 className="car-job__desc-h" key={i}>{b.text}</h3>
                : <p className="car-job__desc" key={i}>{b.text}</p>
          ))}
        </div>

        {/* Own column, under the workplace tag of the row: the action has to be
            in reach from the first line of the description, not only after it. */}
        <div className="car-job__aside">
          <a className="btn btn--blue btn--md car-job__apply"
            href={job.url} target="_blank" rel="noopener noreferrer">
            Candidatar-se no InHire
            <span className="btn__arrow"><SIcon name="btnArrow" /></span>
          </a>
        </div>
      </div>
    </div>
  );
}

/* ------------------------------------------------------------ jobs list

   No local list to fall back to on failure, by design: a stale or invented
   vacancy is the exact problem this page was rebuilt to remove, so a failed
   fetch says so and sends the visitor to the career page itself. */
function VG_Jobs({ feed, chip, setChip, query, setQuery, openId, setOpenId }) {
  const { status, jobs, error } = feed;

  const filtered = jobs.filter((j) => VG_matches(j, chip, query));
  const chips = VG_chips(jobs);
  const countLabel = status !== "ready" ? ""
    : filtered.length === 1 ? "1 vaga encontrada" : `${filtered.length} vagas encontradas`;

  return (
    <section className="section car-jobs">
      <div className="container">
        <div className="car-jobs__head">
          <h2 className="car-h2">Oportunidades</h2>
          <span className="car-jobs__count">{countLabel}</span>
        </div>

        {chips.length > 0 &&
        <div className="car-chips">
          {chips.map((c) => (
            <button
              key={c}
              type="button"
              className={`car-chip ${(chip || "Todas") === c ? "is-active" : ""}`}
              onClick={() => setChip(c)}>
              {c}
            </button>
          ))}
        </div>}

        <div className="car-job-list">
          {status === "loading" &&
            <div className="car-empty car-empty--loading">Carregando as vagas abertas no InHire.</div>}

          {status === "error" &&
            <div className="car-empty">
              Não foi possível carregar as vagas agora ({error}).{" "}
              <a href={VG_IH.SITE + "/vagas"} target="_blank" rel="noopener noreferrer">
                Ver as vagas direto no InHire
              </a>
            </div>}

          {status === "ready" && jobs.length === 0 &&
            <div className="car-empty">
              Nenhuma vaga aberta no momento. Deixe seu currículo no banco de talentos
              logo abaixo e a gente te avisa.
            </div>}

          {status === "ready" && jobs.length > 0 && filtered.length === 0 &&
            <div className="car-empty">
              Nenhuma vaga corresponde à sua busca.{" "}
              <button type="button" className="car-empty__clear"
                onClick={() => { setChip("Todas"); setQuery(""); }}>
                Limpar filtros
              </button>
            </div>}

          {filtered.map((job) => (
            <VG_JobRow
              key={job.id}
              job={job}
              open={openId === job.id}
              onToggle={() => setOpenId(openId === job.id ? "" : job.id)} />
          ))}
        </div>
      </div>
    </section>
  );
}

/* ------------------------------------------------------------ talent bank

   Was a form that answered every submit with "Currículo recebido!" while
   discarding every field, the attached CV included. InHire keeps an open-ended
   "Banco de Talentos" opening of its own, with the upload and the LGPD notice
   the ATS already handles, so the candidacy lands somewhere real and every
   applicant stays in one pipeline. The link is the opening's own address, see
   TALENT_POOL in jobs-data.js: it used to be resolved from the feed at runtime,
   which built it without the slug InHire needs and left the button opening
   nothing. */
function VG_Talent() {
  return (
    <section className="section section--alt">
      <div className="container">
        <div className="car-talent__grid car-talent__grid--cta">
          <div className="car-talent__copy">
            <span className="eyebrow">Banco de talentos</span>
            <h2 className="car-h2">Sua vaga ainda não abriu? Deixe seu currículo com a gente</h2>
            <p className="car-p">
              Cadastre o seu perfil no banco de talentos da Just Travel. Assim que surgir
              uma oportunidade que combine com você, o time de recrutamento entra em
              contato.
            </p>
            <a className="btn btn--blue btn--lg" href={VG_IH.TALENT_POOL} target="_blank" rel="noopener noreferrer">
              Entrar no banco de talentos
              <span className="btn__arrow"><SIcon name="btnArrow" /></span>
            </a>
            <p className="car-form__fine">
              O cadastro acontece no InHire, onde a gente cuida de todas as candidaturas.
            </p>
          </div>
        </div>
      </div>
    </section>
  );
}

/* ------------------------------------------------------------ app */
/* The careers hero has a search box but no list to filter, so it hands the
   query over here in ?q=. Read once, at first render, so the field starts
   filled and the list starts filtered. */
function VG_initialQuery() {
  if (typeof URLSearchParams === "undefined") return "";
  try { return new URLSearchParams(window.location.search).get("q") || ""; }
  catch (_) { return ""; }
}

function VGApp() {
  const [query, setQuery] = React.useState(VG_initialQuery);
  const [chip, setChip] = React.useState("Todas");
  const [openId, setOpenId] = React.useState("");
  // One fetch for the whole page: the list feeds the openings and the talent
  // bank link both.
  const feed = VG_IH.useJobs();

  return (
    <PageShell>
      <VG_Hero query={query} setQuery={setQuery} />
      <VG_Jobs feed={feed} chip={chip} setChip={setChip} query={query} setQuery={setQuery}
        openId={openId} setOpenId={setOpenId} />
      <VG_Talent />
      </PageShell>
  );
}

(function () {
  const el = document.getElementById("app");
  if (!el) return;
  ReactDOM.createRoot(el).render(<VGApp />);
})();
