/* Settings — four registered screens under one namespace, reached from the
   account menu and from each other by the sub-nav, which is the route table
   filtered by parent.

   Commit model, the same on all four: STAGED. Every control is a form field,
   nothing applies until Save, Save and Discard are disabled until dirty. That is
   the opposite of the rest of the product (Instant everywhere else) and it is
   deliberate: these values change what every other screen counts, so nobody
   should change one by brushing a switch.

   The process page edits RD_POLICY itself — the object metrics.js reads. Saving
   it moves the queue, the stepper's service levels, the sidebar badges and the
   compliance screen at once, because there is only one copy of those numbers. */
(() => {
  const {
    Card, CardHeader, CardTitle, CardDescription, CardPanel, CardFooter,
    Table, TableHeader, TableBody, TableRow, TableHead, TableCell,
    Button, Badge, Avatar, Alert, AlertTitle, AlertDescription, Separator, Switch, Select, Checkbox,
    Field, FieldLabel, FieldDescription, FieldError, Input, Textarea,
  } = window.OriginDesignSystem_7c998b;

  function SettingsFrame({ path, title, note, onNavigate, children, actions }) {
    return (
      <div className="rd-page">
        <PageHead path={path} title={title} note={note} actions={actions} />
        <div className="rd-card-tabs">
          <ViewTabs value={path} onSelect={(next) => { if (next !== path) onNavigate(next); }}
            views={settingsPages().map((route) => ({ value: route.path, label: route.label }))} />
        </div>
        {children}
      </div>
    );
  }

  /* ── /settings/desk ────────────────────────────────────────────────────── */
  function DeskSettingsScreen({ data, now, session, onNavigate, desk, onSaveDesk }) {
    const [draft, setDraft] = React.useState(desk);
    React.useEffect(() => setDraft(desk), [desk]);
    const dirty = JSON.stringify(draft) !== JSON.stringify(desk);
    const set = (key, value) => setDraft((d) => Object.assign({}, d, { [key]: value }));
    const errors = {};
    if (!draft.name.trim()) errors.name = "The organisation's name appears on every advert and every email.";
    if (!draft.replyTo.trim() || draft.replyTo.indexOf("@") === -1) errors.replyTo = "A real address — candidates reply to it.";
    const valid = Object.keys(errors).length === 0;

    return (
      <SettingsFrame path="/settings/desk" title="The desk" onNavigate={onNavigate}
        note="Who this desk belongs to, and what candidates see when it writes to them.">
        <div className="rd-columns">
          <Card>
            <CardHeader>
              <CardTitle>Organisation</CardTitle>
              <CardDescription>Used on adverts, offer letters and every email the desk sends.</CardDescription>
            </CardHeader>
            <CardPanel>
              <div className="rd-fields">
                <Field>
                  <FieldLabel htmlFor="st-name">Name</FieldLabel>
                  <Input id="st-name" value={draft.name} invalid={!!errors.name} onChange={(e) => set("name", e.target.value)} />
                  {errors.name ? <FieldError>{errors.name}</FieldError> : null}
                </Field>
                <Field>
                  <FieldLabel htmlFor="st-reply">Reply-to address</FieldLabel>
                  <Input id="st-reply" type="email" value={draft.replyTo} invalid={!!errors.replyTo} onChange={(e) => set("replyTo", e.target.value)} />
                  {errors.replyTo ? <FieldError>{errors.replyTo}</FieldError> : <FieldDescription>Where a candidate's reply goes. It is not a person's inbox on purpose.</FieldDescription>}
                </Field>
                <Field>
                  <FieldLabel htmlFor="st-sign">How the desk signs off</FieldLabel>
                  <Textarea id="st-sign" rows={3} value={draft.signature} onChange={(e) => set("signature", e.target.value)} />
                  <FieldDescription>Goes under every message sent from an application.</FieldDescription>
                </Field>
              </div>
            </CardPanel>
          </Card>

          <Card>
            <CardHeader>
              <CardTitle>Sites and departments</CardTitle>
              <CardDescription>The lists every requisition and every application chooses from.</CardDescription>
            </CardHeader>
            <CardPanel>
              <div className="rd-stack">
                <span className="rd-part">
                  <span className="rd-kv__label">Sites</span>
                  <div className="rd-list">
                    {SITES.map((site) => {
                      const reqs = data.requisitions.filter((r) => r.site === site.value);
                      return (
                        <div className="rd-list__row" key={site.value}>
                          <div className="rd-list__main">
                            <span className="rd-record__name">{site.label}</span>
                            <span className="rd-record__meta">{plural(reqs.length, "requisition", "requisitions")} · {plural(reqs.filter(REQUISITION_FLAGS.isOpen).length, "open", "open")}</span>
                          </div>
                          <div className="rd-list__side">
                            <span className="rd-foot">{reqs.length ? "In use" : "Not used yet"}</span>
                          </div>
                        </div>
                      );
                    })}
                  </div>
                </span>
                <Separator />
                <span className="rd-part">
                  <span className="rd-kv__label">Departments</span>
                  <span className="rd-chips">
                    {DEPARTMENTS.map((department) => (
                      <Badge key={department.value} size="sm" variant="secondary">
                        {department.label} · {data.requisitions.filter((r) => r.department === department.value).length}
                      </Badge>
                    ))}
                  </span>
                  <span className="rd-foot">
                    A site or department in use cannot be removed — {plural(data.requisitions.length, "requisition", "requisitions")} and {plural(data.applications.length, "application", "applications")} point at these.
                    Editing the lists is a data change and belongs with the trust's own establishment records.
                  </span>
                </span>
              </div>
            </CardPanel>
          </Card>
        </div>
        <FormBar dirty={dirty} label="Save the desk" onCancel={() => setDraft(desk)}
          note={dirty ? "Three fields, applied to every advert and message the desk sends." : "Nothing has changed."}
          onSave={() => { if (valid) onSaveDesk(draft); }} />
      </SettingsFrame>
    );
  }

  /* ── /settings/process — the policy every figure reads ─────────────────── */
  function ProcessSettingsScreen({ data, now, session, onNavigate, policy, onSavePolicy }) {
    const [draft, setDraft] = React.useState(() => JSON.parse(JSON.stringify(policy)));
    React.useEffect(() => setDraft(JSON.parse(JSON.stringify(policy))), [policy]);
    const dirty = JSON.stringify(draft) !== JSON.stringify(policy);
    const setDays = (stage, value) => setDraft((d) => Object.assign({}, d, { stageDays: Object.assign({}, d.stageDays, { [stage]: Number(value) }) }));
    const set = (key, value) => setDraft((d) => Object.assign({}, d, { [key]: Number(value) }));
    const numbers = [1, 2, 3, 4, 5, 6, 7, 10, 14, 21, 30, 45, 60, 90];
    const items = (list) => list.map((n) => ({ value: String(n), label: String(n) }));
    /* Live, over the real array, at the draft's numbers: what saving would do. */
    const wouldBeOver = liveApplications(data.applications).filter((a) => {
      const allowed = draft.stageDays[a.stage];
      return allowed && daysInStage(a, now) > allowed;
    });
    const isOver = stalledApplications(data.applications, now);

    return (
      <SettingsFrame path="/settings/process" title="Process and service levels" onNavigate={onNavigate}
        note="How long each step of the process is allowed to take, and what a decision needs before it can be made. These are the numbers every other screen counts against.">

        <Alert variant={dirty && wouldBeOver.length !== isOver.length ? "warning" : "info"}>
          <Icon name={dirty && wouldBeOver.length !== isOver.length ? "triangle-alert" : "info"} size={16} />
          <AlertTitle>
            {dirty && wouldBeOver.length !== isOver.length
              ? plural(wouldBeOver.length, "application", "applications") + " would be over its service level, against " + isOver.length + " today"
              : plural(isOver.length, "application", "applications") + " over its service level at these numbers"}
          </AlertTitle>
          <AlertDescription>
            Run against the {liveApplications(data.applications).length} live applications as they stand, so the effect of a change is visible before it is saved.
            {wouldBeOver.length ? " " + wouldBeOver.slice(0, 4).map((a) => a.candidate.name.split(" ")[0] + " (" + statusValue(APPLICATION_STAGE, a.stage).label.toLowerCase() + ")").join(", ") + (wouldBeOver.length > 4 ? " and " + (wouldBeOver.length - 4) + " more" : "") + "." : ""}
          </AlertDescription>
        </Alert>

        <div className="rd-columns">
          <Card>
            <CardHeader>
              <CardTitle>Service level per step</CardTitle>
              <CardDescription>In days. Each step gets its own, which is why "over its service level" is answered per stage and never with one number for the whole desk.</CardDescription>
            </CardHeader>
            <CardPanel>
              <div className="rd-stack rd-stack--tight">
                {APPLICATION_PATH.filter((stage) => draft.stageDays[stage] !== undefined).map((stage) => {
                  const here = applicationsAtStage(liveApplications(data.applications), stage);
                  return (
                    <div className="rd-setting" key={stage}>
                      <span className="rd-setting__text">
                        <span className="rd-setting__label">{statusValue(APPLICATION_STAGE, stage).label}</span>
                        <span className="rd-foot">{STAGE_MEANS[stage]} · {plural(here.length, "application", "applications")} here now</span>
                      </span>
                      <span className="rd-setting__control">
                        <label className="rd-sr" htmlFor={"st-days-" + stage}>{statusValue(APPLICATION_STAGE, stage).label} service level in days</label>
                        <Select id={"st-days-" + stage} size="sm" items={items(numbers.filter((n) => n <= 30))}
                          value={String(draft.stageDays[stage])} onValueChange={(v) => setDays(stage, v)} />
                        <span className="rd-foot">days</span>
                      </span>
                    </div>
                  );
                })}
              </div>
            </CardPanel>
            <CardFooter className="rd-card-foot">
              <span className="rd-foot">Checks is the longest on purpose: referees and the disclosure service are not ours to hurry.</span>
            </CardFooter>
          </Card>

          <Card>
            <CardHeader>
              <CardTitle>What a decision needs</CardTitle>
              <CardDescription>The preconditions the primary action on an application checks before it will move.</CardDescription>
            </CardHeader>
            <CardPanel>
              <div className="rd-stack rd-stack--tight">
                {[
                  { key: "panelScorecards", label: "Scorecards before checks", note: "From different people. " + data.applications.filter((a) => a.stage === "panel" && scoresOf(a).count < draft.panelScorecards).length + " application(s) at panel would be short.", list: [1, 2, 3, 4] },
                  { key: "referencesRequired", label: "References before an offer", note: "NHS standard is two, one the current employer.", list: [1, 2, 3] },
                  { key: "offerValidDays", label: "An offer is valid for", note: "Days. Extending one is a decision with a reason attached.", list: [3, 5, 7, 10, 14, 21] },
                  { key: "registrationWarnDays", label: "Flag a registration renewing inside", note: "Days. " + complianceRows(data.applications, data.requisitions, now).filter((r) => r.application.registrationExpiresAt && daysBetween(now, r.application.registrationExpiresAt) <= draft.registrationWarnDays).length + " would be flagged on Compliance.", list: [30, 45, 60, 90] },
                  { key: "offerExpiryWarnDays", label: "Badge an offer inside", note: "Days of running out. " + offersAwaitingAnswer(data.applications).filter((a) => daysBetween(now, a.offer.expiresAt) <= draft.offerExpiryWarnDays).length + " would be on the badge.", list: [1, 2, 3, 5, 7] },
                  { key: "thinPipeline", label: "A pipeline is thin under", note: "Live applications per requisition. " + data.requisitions.filter((r) => r.status === "open" && liveApplications(applicationsFor(data.applications, r.id)).length < draft.thinPipeline).length + " open requisition(s) would be flagged.", list: [2, 3, 4, 5, 6] },
                  { key: "agingDays", label: "A requisition is aging after", note: "Days open. " + data.requisitions.filter((r) => r.status === "open" && daysBetween(r.openedAt, now) > draft.agingDays).length + " would be flagged.", list: [30, 45, 60, 90] },
                ].map((row) => (
                  <div className="rd-setting" key={row.key}>
                    <span className="rd-setting__text">
                      <span className="rd-setting__label">{row.label}</span>
                      <span className="rd-foot">{row.note}</span>
                    </span>
                    <span className="rd-setting__control">
                      <label className="rd-sr" htmlFor={"st-" + row.key}>{row.label}</label>
                      <Select id={"st-" + row.key} size="sm" items={items(row.list)} value={String(draft[row.key])} onValueChange={(v) => set(row.key, v)} />
                    </span>
                  </div>
                ))}
              </div>
            </CardPanel>
          </Card>
        </div>

        <FormBar dirty={dirty} label="Save the process" onCancel={() => setDraft(JSON.parse(JSON.stringify(policy)))}
          note={dirty
            ? "There is one copy of these numbers: saving moves the queue, the stepper, the sidebar badges and Compliance at the same moment."
            : "Nothing has changed. Every screen is counting against these numbers now."}
          onSave={() => onSavePolicy(draft)} />
      </SettingsFrame>
    );
  }

  /* ── /settings/channels ────────────────────────────────────────────────── */
  function ChannelSettingsScreen({ data, now, session, onNavigate, channels, onSaveChannels }) {
    const [draft, setDraft] = React.useState(channels);
    React.useEffect(() => setDraft(channels), [channels]);
    const dirty = JSON.stringify(draft) !== JSON.stringify(channels);
    const toggle = (value) => setDraft((d) => Object.assign({}, d, {
      enabled: d.enabled.indexOf(value) > -1 ? d.enabled.filter((v) => v !== value) : d.enabled.concat([value]),
      defaults: d.enabled.indexOf(value) > -1 ? d.defaults.filter((v) => v !== value) : d.defaults,
    }));
    const toggleDefault = (value) => setDraft((d) => Object.assign({}, d, {
      defaults: d.defaults.indexOf(value) > -1 ? d.defaults.filter((v) => v !== value) : d.defaults.concat([value]),
    }));
    /* Usage is counted from the adverts and applications, not stored here. */
    const usage = (value) => ({
      posted: data.adverts.filter((ad) => ad.postedTo.some((p) => p.channel === value)).length,
      applications: data.applications.filter((a) => a.source === value).length,
    });
    const errors = {};
    if (!draft.enabled.length) errors.enabled = "At least one channel, or a requisition cannot be advertised anywhere.";

    return (
      <SettingsFrame path="/settings/channels" title="Adverts and channels" onNavigate={onNavigate}
        note="Where adverts may be posted, what a new advert starts as, and how long a posting stays up before the desk is asked about it.">
        <div className="rd-columns">
          <Card>
            <CardHeader>
              <CardTitle>Channels</CardTitle>
              <CardDescription>A channel a requisition may be posted to. Turning one off leaves existing postings alone.</CardDescription>
            </CardHeader>
            <CardPanel>
              <div className="rd-stack rd-stack--tight">
                {SOURCES.filter((source) => source.value !== "pool").map((source) => {
                  const on = draft.enabled.indexOf(source.value) > -1;
                  const used = usage(source.value);
                  return (
                    <div className="rd-setting" key={source.value}>
                      <span className="rd-setting__text">
                        <span className="rd-setting__label">{source.label}</span>
                        <span className="rd-foot">
                          {used.posted ? plural(used.posted, "advert", "adverts") + " posted there" : "Not posted anywhere"}
                          {" · " + plural(used.applications, "application", "applications") + " came from it"}
                        </span>
                      </span>
                      <span className="rd-setting__control">
                        {on ? (
                          <label className="rd-check">
                            <Checkbox checked={draft.defaults.indexOf(source.value) > -1} onCheckedChange={() => toggleDefault(source.value)}
                              aria-label={"Post new adverts to " + source.label + " by default"} />
                            <span className="rd-check__text"><span className="rd-foot">By default</span></span>
                          </label>
                        ) : null}
                        <Switch checked={on} onCheckedChange={() => toggle(source.value)} aria-label={source.label + " available for adverts"} />
                      </span>
                    </div>
                  );
                })}
                {errors.enabled ? <FieldError>{errors.enabled}</FieldError> : null}
              </div>
            </CardPanel>
            <CardFooter className="rd-card-foot">
              <span className="rd-foot">
                The talent pool is not a channel: it is people we already know, and applications from it are created here rather than applied for.
              </span>
            </CardFooter>
          </Card>

          <Card>
            <CardHeader>
              <CardTitle>Postings</CardTitle>
              <CardDescription>The two rules the desk keeps about live adverts.</CardDescription>
            </CardHeader>
            <CardPanel>
              <div className="rd-stack rd-stack--tight">
                <div className="rd-setting">
                  <span className="rd-setting__text">
                    <span className="rd-setting__label">Ask about a posting after</span>
                    <span className="rd-foot">
                      Days up. {data.adverts.reduce((n, ad) => n + ad.postedTo.filter((p) => daysBetween(p.postedAt, now) > draft.reviewDays).length, 0)} posting(s) are older than that now.
                    </span>
                  </span>
                  <span className="rd-setting__control">
                    <label className="rd-sr" htmlFor="st-review">Ask about a posting after</label>
                    <Select id="st-review" size="sm" value={String(draft.reviewDays)} onValueChange={(v) => setDraft((d) => Object.assign({}, d, { reviewDays: Number(v) }))}
                      items={[14, 21, 28, 42, 60].map((n) => ({ value: String(n), label: n + " days" }))} />
                  </span>
                </div>
                <div className="rd-setting">
                  <span className="rd-setting__text">
                    <span className="rd-setting__label">Take adverts down when the seat is filled</span>
                    <span className="rd-foot">
                      {data.requisitions.filter((r) => r.status === "filled").length} filled requisition(s) — {data.adverts.filter((ad) => ad.postedTo.length && data.requisitions.some((r) => r.id === ad.requisitionId && r.status === "filled")).length} still has a posting on the record.
                    </span>
                  </span>
                  <span className="rd-setting__control">
                    <Switch checked={draft.autoUnpost} onCheckedChange={(v) => setDraft((d) => Object.assign({}, d, { autoUnpost: v }))}
                      aria-label="Take adverts down when the seat is filled" />
                  </span>
                </div>
              </div>
            </CardPanel>
          </Card>
        </div>
        <FormBar dirty={dirty} label="Save channels" onCancel={() => setDraft(channels)}
          note={dirty
            ? plural(draft.enabled.length, "channel", "channels") + " available, " + plural(draft.defaults.length, "on", "on") + " by default for a new advert."
            : "Nothing has changed."}
          onSave={() => { if (!Object.keys(errors).length) onSaveChannels(draft); }} />
      </SettingsFrame>
    );
  }

  /* ── /settings/people ──────────────────────────────────────────────────── */
  const CAN = [
    { key: "review", label: "Read and move applications", roles: ["recruiter", "coordinator", "lead"] },
    { key: "book", label: "Book interviews", roles: ["recruiter", "coordinator", "lead"] },
    { key: "score", label: "File scorecards", roles: ["hiring_manager", "panel", "recruiter", "lead"] },
    { key: "offer", label: "Send offers", roles: ["recruiter", "lead"] },
    { key: "premium", label: "Approve money above the band", roles: ["lead"] },
    { key: "settings", label: "Change these settings", roles: ["lead"] },
  ];

  function PeopleSettingsScreen({ data, now, session, onNavigate, onInviteMember, onChangeRole }) {
    const me = staffById(data.staff, session.personId);
    const canChange = me.role === "lead";
    return (
      <SettingsFrame path="/settings/people" title="People and access" onNavigate={onNavigate}
        note={plural(data.staff.length, "person", "people") + " on this desk. What each role may do is fixed by the role, not per person, so there is one answer to \u201cwho can send an offer\u201d."}
        actions={<Button size="sm" disabled={!canChange} onClick={onInviteMember}><Icon name="user-round-plus" size={14} />Invite somebody</Button>}>

        {canChange ? null : (
          <Alert variant="info">
            <Icon name="info" size={16} />
            <AlertTitle>You can read this, not change it</AlertTitle>
            <AlertDescription>
              Roles and invitations are the head of resourcing's — {staffById(data.staff, "p-amara").name}. You are signed in as {labelOf(DESK_ROLES, me.role).toLowerCase()}.
            </AlertDescription>
          </Alert>
        )}

        <Card>
          <CardHeader>
            <CardTitle>The desk</CardTitle>
            <CardDescription>Owned applications and outstanding scorecards are counted from the live arrays, not from a field on the person.</CardDescription>
          </CardHeader>
          <div className="rd-card-table">
            <Table variant="card">
              <TableHeader>
                <TableRow>
                  <TableHead>Person</TableHead>
                  <TableHead className="rd-drop-md">Department</TableHead>
                  <TableHead>Role</TableHead>
                  <TableHead className="rd-num">Owns</TableHead>
                  <TableHead className="rd-num rd-drop-lg">Scorecards owed</TableHead>
                  <TableHead className="rd-actions-head">Action</TableHead>
                </TableRow>
              </TableHeader>
              <TableBody>
                {data.staff.map((person) => {
                  const owned = liveApplications(ownedBy(data.applications, person.id)).length;
                  const owed = feedbackOutstanding(data.interviews).filter((iv) => iv.panelIds.indexOf(person.id) > -1).length;
                  return (
                    <TableRow key={person.id}>
                      <TableCell><StaffCell person={person} meta={person.email} /></TableCell>
                      <TableCell className="rd-drop-md">{labelOf(DEPARTMENTS, person.department)}</TableCell>
                      <TableCell>
                        <span className="rd-status">
                          <Badge size="sm" variant={person.role === "lead" ? "info" : "secondary"}>{labelOf(DESK_ROLES, person.role)}</Badge>
                          {person.id === me.id ? <span className="rd-foot">you</span> : null}
                        </span>
                      </TableCell>
                      <TableCell className="rd-num">{owned || "—"}</TableCell>
                      <TableCell className="rd-num rd-drop-lg">{owed || "—"}</TableCell>
                      <TableCell className="rd-actions">
                        <Button variant="outline" size="xs" disabled={!canChange || person.id === me.id}
                          onClick={() => onChangeRole(person)}>Change role</Button>
                      </TableCell>
                    </TableRow>
                  );
                })}
              </TableBody>
            </Table>
          </div>
          <CardFooter className="rd-card-foot">
            <span className="rd-foot">You cannot change your own role — that is what stops the last head of resourcing locking everybody out.</span>
          </CardFooter>
        </Card>

        <Card>
          <CardHeader>
            <CardTitle>What each role may do</CardTitle>
            <CardDescription>Fixed by role. One row per permission, one column per role, on one set of tracks.</CardDescription>
          </CardHeader>
          <CardPanel>
            <div className="rd-matrix" style={{ gridTemplateColumns: "minmax(0,1.4fr) " + DESK_ROLES.map(() => "minmax(0,1fr)").join(" ") }}>
              <span className="rd-matrix__head">Permission</span>
              {DESK_ROLES.map((role) => <span className="rd-matrix__head" key={role.value}>{role.label}</span>)}
              {CAN.map((permission) => (
                <React.Fragment key={permission.key}>
                  <span>{permission.label}</span>
                  {DESK_ROLES.map((role) => (
                    <span className="rd-matrix__cell" key={role.value + permission.key}>
                      {permission.roles.indexOf(role.value) > -1
                        ? <Icon name="check" size={14} />
                        : <span className="rd-muted">—</span>}
                    </span>
                  ))}
                </React.Fragment>
              ))}
            </div>
          </CardPanel>
          <CardFooter className="rd-card-foot">
            <span className="rd-foot">
              {plural(data.staff.filter((p) => p.role === "lead").length, "person", "people")} can approve money above a band and change these settings.
              A desk with one is a desk that stops when they are on leave.
            </span>
          </CardFooter>
        </Card>
      </SettingsFrame>
    );
  }

  Object.assign(window, { DeskSettingsScreen, ProcessSettingsScreen, ChannelSettingsScreen, PeopleSettingsScreen });
})();
