/* Upkeep and providers — the work the house needs, one job's record, and the
   people who do it.
   Commit model: INSTANT on all three. Moving a job applies immediately with an
   undo toast; asking for a quote, booking and rescheduling need a date or a
   price, so they open a staged dialog from App.jsx; cancelling a job is
   irreversible and confirms.

   A consumable's due state is read off its device's hours, so a filter falls
   overdue without anybody writing on the job. */
(() => {
  const {
    Button, Badge, Alert, AlertTitle, AlertDescription, Avatar, Tabs, TabsList, TabsTab,
    Table, TableHeader, TableBody, TableRow, TableHead, TableCell,
  } = window.OriginDesignSystem_7c998b;

  const KIND_FILTER = [{ value: "all", label: "Every kind" }].concat(JOB_KINDS);

  function UpkeepScreen({ data, now, viewer, onNavigate, onJobTransition, onNewJob, onExport }) {
    const [tab, setTab] = React.useState("open");
    const [query, setQuery] = React.useState("");
    const [kind, setKind] = React.useState("all");
    const { sort, onSort } = useSort("due", "asc");

    const jobs = jobRows(data, now);
    const open = jobsOpen(jobs);
    const overdue = jobsOverdue(jobs);
    const needy = jobsNeedingYou(jobs);
    const booked = jobsBooked(jobs);
    const quoted = jobsAwaitingQuote(jobs);
    const consumables = jobs.filter((j) => j.kind === "consumable");

    const dirty = !!query || kind !== "all";
    const clear = () => { setQuery(""); setKind("all"); };
    const base = tab === "open" ? open : tab === "needs" ? needy : tab === "booked" ? booked : tab === "done" ? jobsDone(jobs) : jobs;
    const filtered = base.filter((job) => {
      if (kind !== "all" && job.kind !== kind) return false;
      if (query && (job.title + " " + (job.note || "") + " " + providerName(data.providers, job.providerId)).toLowerCase().indexOf(query.toLowerCase()) < 0) return false;
      return true;
    });
    const rows = sortRows(filtered, sort, {
      due: (j) => j.dueAt,
      cost: (j) => j.costMinor || j.quoteMinor || 0,
      title: (j) => j.title,
    });

    return (
      <>
        <PageHead path="/upkeep" title="Upkeep"
          lede={open.length + " jobs open on the house. " + (overdue.length ? overdue.length + " are past their date, and a consumable's date is the hours its machine has actually run." : "Nothing is past its date.")}
          actions={
            <>
              <Button variant="outline" size="sm" onClick={() => onNavigate("/providers")}><Icon name="hard-hat" />Providers</Button>
              <ExportMenu scope={dirty || tab !== "open" ? rows.length + " jobs in this list" : open.length + " open jobs"}
                onExport={(format) => onExport("Upkeep", dirty || tab !== "open" ? "The filtered job list" : "Open jobs", rows.length, format)} />
              <Button size="sm" onClick={onNewJob}><Icon name="plus" />New job</Button>
            </>
          } />

        <Figures items={[
          { label: "Open", value: open.length, qualifier: overdue.length + " past their date, " + jobsBooked(jobs).length + " booked in" },
          { label: "Wanting a decision", value: needy.length, qualifier: quoted.length + " quoted, " + consumables.filter((c) => c.spent).length + " consumables spent" },
          { label: "Committed", value: formatPounds(committedSpend(jobs)), qualifier: "across " + open.filter((j) => (j.costMinor || j.quoteMinor)).length + " jobs with a price or a quote against them" },
          { label: "Done this year", value: jobsDone(jobs).length, qualifier: jobsDone(jobs).length ? formatPounds(jobsDone(jobs).reduce((n, j) => n + (j.costMinor || 0), 0)) + " spent, most recently " + formatWhen(jobsDone(jobs)[0].dueAt, now) : "nothing completed yet" },
        ]} />

        {consumables.some((c) => c.spent) ? (
          <Band>
            <Card tint>
              <Alert variant="warning">
                <AlertTitle>{consumables.filter((c) => c.spent).length === 1 ? "A consumable is past its interval" : consumables.filter((c) => c.spent).length + " consumables are past their interval"}</AlertTitle>
                <AlertDescription>
                  {consumables.filter((c) => c.spent).map((c) => c.title + " — " + c.device.name + " has run " + formatCount(c.ranHours) + " hours of a " + formatCount(c.lifeHours) + "-hour interval, " + formatCount(c.ranHours - c.lifeHours) + " past the change").join(" · ")}.
                  The hours come off the machine, so this does not depend on anybody remembering a date.
                </AlertDescription>
              </Alert>
            </Card>
          </Band>
        ) : null}

        <Band>
          <Card flush>
            <div style={{ padding: "0 var(--card-pad) var(--space-4)" }}>
              <Tabs value={tab} onValueChange={setTab}>
                <TabsList>
                  <TabsTab value="open" size="sm">Open ({open.length})</TabsTab>
                  <TabsTab value="needs" size="sm">Needs you ({needy.length})</TabsTab>
                  <TabsTab value="booked" size="sm">Booked ({booked.length})</TabsTab>
                  <TabsTab value="done" size="sm">Done ({jobsDone(jobs).length})</TabsTab>
                  <TabsTab value="all" size="sm">All ({jobs.length})</TabsTab>
                </TabsList>
              </Tabs>
            </div>
            <FilterBar query={query} onQuery={setQuery} placeholder="Search a job, a note or a provider…" dirty={dirty} onClear={clear}
              selects={[{ id: "kind", label: "Kind", items: KIND_FILTER, value: kind, onChange: setKind }]} />
            {rows.length === 0 ? <NoResults noun="jobs" onClear={clear} /> : (
              <>
                <TableWrap>
                  <Table>
                    <TableHeader>
                      <TableRow>
                        <TableHead><SortHead label="Job" sortKey="title" sort={sort} onSort={onSort} /></TableHead>
                        <TableHead>Kind</TableHead>
                        <TableHead>Status</TableHead>
                        <TableHead>Who</TableHead>
                        <TableHead><SortHead label="Due" sortKey="due" sort={sort} onSort={onSort} /></TableHead>
                        <TableHead style={{ minWidth: "9rem" }}>Life left</TableHead>
                        <TableHead className="hh-num"><SortHead label="Price" sortKey="cost" sort={sort} onSort={onSort} /></TableHead>
                        <TableHead>Action</TableHead>
                      </TableRow>
                    </TableHeader>
                    <TableBody>
                      {rows.map((job) => (
                        <TableRow key={job.id}>
                          <TableCell>
                            <span className="hh-person__text">
                              <span className="hh-person__name"><button type="button" className="hh-linkbtn" onClick={() => onNavigate("/upkeep/" + job.id)}>{job.title}</button></span>
                              <span className="hh-person__meta">{job.room ? roomName(job.room) : "The whole house"}</span>
                            </span>
                          </TableCell>
                          <TableCell>{labelOf(JOB_KINDS, job.kind)}</TableCell>
                          <TableCell>
                            <span className="hh-actions__row">
                              <StatusBadge values={JOB_STATUS} value={job.status} />
                              {job.overdue ? <Badge size="sm" variant="warning">{formatCountdown(job.dueAt, now)}</Badge> : null}
                            </span>
                          </TableCell>
                          <TableCell>{job.providerId ? <button type="button" className="hh-linkbtn" onClick={() => onNavigate("/providers/" + job.providerId)}>{providerName(data.providers, job.providerId)}</button> : <span className="hh-muted">Nobody booked</span>}</TableCell>
                          <TableCell><Clock at={job.dueAt} now={now} problem={job.status !== "done" && job.status !== "cancelled"} /></TableCell>
                          <TableCell>
                            {job.lifeHours != null ? (
                              <span style={{ display: "flex", flexDirection: "column", gap: 4, minWidth: "8rem" }}>
                                <span className="hh-footnote">{formatCount(job.ranHours)} of {formatCount(job.lifeHours)} hours</span>
                                <Bar percent={Math.max(0, (job.lifeLeft || 0) * 100)} tone={job.spent ? "danger" : job.lifeLeft < 0.2 ? "warn" : null} label="Life left" />
                              </span>
                            ) : <span className="hh-muted">—</span>}
                          </TableCell>
                          <TableCell className="hh-num">{job.costMinor ? formatPounds(job.costMinor) : job.quoteMinor ? formatPounds(job.quoteMinor) + " quoted" : <span className="hh-muted">—</span>}</TableCell>
                          <TableCell><RowActions transitions={jobTransitions(job, viewer)} onRun={(t) => onJobTransition(job, t)} label={"Actions for " + job.title} /></TableCell>
                        </TableRow>
                      ))}
                    </TableBody>
                  </Table>
                </TableWrap>
                <TableFoot shown={rows.length} total={jobs.length} noun="jobs" />
              </>
            )}
          </Card>
        </Band>
      </>
    );
  }

  function JobScreen({ data, now, viewer, jobId, onNavigate, onJobTransition, onExport }) {
    const job = jobRows(data, now).find((j) => j.id === jobId);
    const provider = job.providerId ? providerById(data.providers, job.providerId) : null;
    const contract = provider ? data.contracts.find((c) => c.providerId === provider.id && c.status === "active") : null;
    const events = eventsForJob(data.events, job.id);

    return (
      <>
        <PageHead path="/upkeep/:id" params={{ id: job.id }} crumb={job.title} title={job.title}
          lede={labelOf(JOB_KINDS, job.kind) + (job.room ? " · " + roomName(job.room) : " · the whole house") + (job.device ? " · " + job.device.name : "")}
          actions={<ExportMenu scope="This job and its history" onExport={(format) => onExport("Job", job.title, 1, format)} />} />

        <Band>
          <Card>
            <div style={{ display: "flex", flexWrap: "wrap", alignItems: "flex-start", justifyContent: "space-between", gap: "var(--space-5)" }}>
              <div style={{ minWidth: 0, flex: "1 1 22rem" }}>
                <span className="hh-actions__row" style={{ marginBottom: "var(--space-2)" }}>
                  <StatusBadge values={JOB_STATUS} value={job.status} />
                  {job.overdue ? <Badge size="sm" variant="warning">{formatCountdown(job.dueAt, now)}</Badge> : null}
                  {job.spent ? <Badge size="sm" variant="warning">Interval spent</Badge> : null}
                </span>
                <p className="hh-card__note">{job.note}</p>
              </div>
              <Transitions transitions={jobTransitions(job, viewer)} onRun={(t) => onJobTransition(job, t)} />
            </div>
          </Card>
        </Band>

        <div className="hh-cols">
          <div>
            <Card title="The job">
              <Pairs items={[
                { label: "Status", value: <StatusBadge values={JOB_STATUS} value={job.status} /> },
                { label: "Due", value: <Clock at={job.dueAt} now={now} problem={job.status !== "done" && job.status !== "cancelled"} /> },
                { label: "Booked for", value: job.scheduledAt ? formatWhen(job.scheduledAt, now) : "Not booked" },
                { label: "Who", value: provider ? <button type="button" className="hh-linkbtn" onClick={() => onNavigate("/providers/" + provider.id)}>{provider.name}</button> : "Nobody booked" },
                { label: "Price", value: job.costMinor ? formatPoundsExact(job.costMinor) : job.quoteMinor ? formatPoundsExact(job.quoteMinor) + " quoted" : "No price yet" },
                { label: "Under contract", value: contract ? contract.name : "Charged as it comes" },
                { label: "Device", value: job.device ? <button type="button" className="hh-linkbtn" onClick={() => onNavigate("/devices/" + job.device.id)}>{job.device.name}</button> : "None" },
                { label: "Where", value: job.room ? roomName(job.room) : "The whole house" },
              ]} />
            </Card>

            {job.lifeHours != null ? (
              <Card tint title="Measured in hours, not months" note="The interval is read off the machine, so nobody has to remember a date.">
                <div style={{ marginBottom: "var(--space-3)" }}>
                  <Bar percent={Math.max(0, (job.lifeLeft || 0) * 100)} tone={job.spent ? "danger" : job.lifeLeft < 0.2 ? "warn" : null} label="Life left" />
                </div>
                <Rows>
                  <Row title="Hours run" value={formatCount(job.ranHours)} note={job.device ? "Read from " + job.device.name : "Recorded on the job"} />
                  <Row title="Interval" value={formatCount(job.lifeHours)} note={job.spent ? formatCount(job.ranHours - job.lifeHours) + " hours past the change" : formatCount(job.lifeHours - job.ranHours) + " hours to go"} />
                </Rows>
              </Card>
            ) : null}
          </div>

          <div>
            <Card title={"In the log (" + events.length + ")"} note="Everything the house recorded about this job.">
              {events.length ? (
                <Rows>
                  {events.map((event) => (
                    <Row key={event.id} title={event.line} note={event.note || labelOf(EVENT_KINDS, event.kind)}
                      value={<span className="hh-footnote" title={formatAbsolute(event.at)}>{formatWhen(event.at, now)}</span>} />
                  ))}
                </Rows>
              ) : <p className="hh-footnote">Nothing about this job has reached the log yet.</p>}
            </Card>

            {provider ? (
              <Card title="Who does it" note="What else this provider has done for the house.">
                <Rows>
                  <Row title={<PersonCell name={provider.name} meta={labelOf(TRADES, provider.trade) + " · " + provider.contact} onOpen={() => onNavigate("/providers/" + provider.id)} />}
                    note={provider.phone + " · " + (provider.keyHolder ? "holds a way in" : "no access held")} />
                  {jobsForProvider(jobRows(data, now), provider.id).filter((j) => j.id !== job.id).map((other) => (
                    <Row key={other.id} title={<button type="button" className="hh-linkbtn" onClick={() => onNavigate("/upkeep/" + other.id)}>{other.title}</button>}
                      note={statusValue(JOB_STATUS, other.status).label + " · " + (other.scheduledAt ? formatWhen(other.scheduledAt, now) : "due " + formatWhen(other.dueAt, now))} />
                  ))}
                </Rows>
              </Card>
            ) : null}
          </div>
        </div>
      </>
    );
  }

  function ProvidersScreen({ data, now, viewer, onNavigate, onNewProvider, onExport }) {
    const jobs = jobRows(data, now);
    const withCounts = data.providers.map((provider) => {
      const theirs = jobsForProvider(jobs, provider.id);
      const done = theirs.filter((j) => j.status === "done");
      const openJobs = jobsOpen(theirs);
      const contract = data.contracts.find((c) => c.providerId === provider.id && c.status === "active") || null;
      const grants = grantsForProvider(data.grants, provider.id);
      const lastVisit = theirs.filter((j) => j.scheduledAt).sort((a, b) => b.scheduledAt - a.scheduledAt)[0];
      return { provider: provider, jobs: theirs, done: done, open: openJobs, contract: contract, grants: grants, lastVisit: lastVisit };
    });
    const keyHolders = withCounts.filter((row) => row.grants.some((g) => g.status === "active"));

    return (
      <>
        <PageHead path="/providers" title="Providers"
          lede={data.providers.length + " people and firms the house uses. " + keyHolders.length + " of them hold a way in, and " + contractsActive(data.contracts).length + " are on a contract."}
          actions={
            <>
              <ExportMenu scope={"All " + data.providers.length + " providers"} onExport={(format) => onExport("Providers", "Every provider and their jobs", data.providers.length, format)} />
              <Button size="sm" onClick={onNewProvider}><Icon name="plus" />New provider</Button>
            </>
          } />

        <Figures items={[
          { label: "Providers", value: data.providers.length, qualifier: TRADES.filter((t) => data.providers.some((p) => p.trade === t.value)).length + " trades covered" },
          { label: "On a contract", value: contractsActive(data.contracts).length, qualifier: formatPounds(monthlyCommitted(data.contracts)) + " a month committed" },
          { label: "Holding a way in", value: keyHolders.length, qualifier: keyHolders.map((r) => r.provider.name.split(" ")[0]).join(", ") || "nobody holds access" },
          { label: "Open jobs between them", value: jobsOpen(jobs).filter((j) => j.providerId).length, qualifier: jobsOpen(jobs).filter((j) => !j.providerId).length + " more open jobs have nobody booked" },
        ]} />

        <div className="hh-roomgrid">
          {withCounts.map((row) => (
            <Card key={row.provider.id} fill>
              <div className="hh-room__top">
                <div style={{ minWidth: 0 }}>
                  <div className="hh-room__name"><button type="button" className="hh-linkbtn" onClick={() => onNavigate("/providers/" + row.provider.id)}>{row.provider.name}</button></div>
                  <div className="hh-footnote">{labelOf(TRADES, row.provider.trade)} · {row.provider.contact}</div>
                </div>
                {row.contract ? <Badge size="sm" variant="info">On contract</Badge> : null}
              </div>
              <Rows>
                <Row title="Jobs" value={row.jobs.length} note={row.done.length + " done, " + row.open.length + " open"} />
                <Row title="Last here" value={row.lastVisit ? formatWhen(row.lastVisit.scheduledAt, now) : "—"} note={row.lastVisit ? row.lastVisit.title : "No visit on the record"} />
                <Row title="Access" value={row.grants.filter((g) => g.status === "active").length || "None"}
                  note={row.grants.length ? row.grants.map((g) => g.label + " — " + statusValue(ACCESS_STATUS, g.status).label.toLowerCase()).join(", ") : "No code or key held"} />
              </Rows>
              <div className="hh-room__foot">
                <span className="hh-footnote">{row.provider.hourlyMinor ? formatPounds(row.provider.hourlyMinor) + " an hour" : "Monitoring only"} · since {formatSince(row.provider.since)}</span>
                <Button variant="outline" size="sm" onClick={() => onNavigate("/providers/" + row.provider.id)}>Open</Button>
              </div>
            </Card>
          ))}
        </div>
      </>
    );
  }

  function ProviderScreen({ data, now, viewer, providerId, onNavigate, onJobTransition, onAccessTransition, onExport }) {
    const provider = providerById(data.providers, providerId);
    const jobs = jobsForProvider(jobRows(data, now), provider.id);
    const contract = data.contracts.find((c) => c.providerId === provider.id) || null;
    const grants = grantsForProvider(data.grants, provider.id);
    const spent = jobs.filter((j) => j.status === "done").reduce((n, j) => n + (j.costMinor || 0), 0);

    return (
      <>
        <PageHead path="/providers/:id" params={{ id: provider.id }} crumb={provider.name} title={provider.name}
          lede={labelOf(TRADES, provider.trade) + " · " + provider.contact + " · " + provider.phone}
          actions={<ExportMenu scope={"This provider and their " + jobs.length + " jobs"} onExport={(format) => onExport("Provider", provider.name, 1, format)} />} />

        <Figures items={[
          { label: "Jobs", value: jobs.length, qualifier: jobs.filter((j) => j.status === "done").length + " done, " + jobsOpen(jobs).length + " open" },
          { label: "Spent with them", value: formatPounds(spent), qualifier: "across the jobs marked done" },
          { label: "Ways in held", value: grants.filter((g) => g.status === "active").length, qualifier: grants.length ? grants.map((g) => statusValue(ACCESS_STATUS, g.status).label.toLowerCase()).join(", ") : "no code or key" },
          { label: "Rate", value: provider.hourlyMinor ? formatPounds(provider.hourlyMinor) : "—", unit: provider.hourlyMinor ? "an hour" : "", qualifier: contract ? contract.name : "no contract, charged as it comes" },
        ]} />

        <div className="hh-cols">
          <div>
            <Card title="Record">
              <Pairs items={[
                { label: "Trade", value: labelOf(TRADES, provider.trade) },
                { label: "Contact", value: provider.contact },
                { label: "Phone", value: provider.phone },
                { label: "Email", value: provider.email },
                { label: "Used since", value: formatSince(provider.since) },
                { label: "Holds a way in", value: provider.keyHolder ? "Yes" : "No" },
              ]} />
              <p className="hh-card__note" style={{ marginTop: "var(--space-4)" }}>{provider.note}</p>
            </Card>

            {contract ? (
              <Card tint title="Contract">
                <Rows>
                  <Row title={contract.name} value={formatPounds(contract.monthlyMinor) + " a month"} note={contract.note} />
                  <Row title="Runs to" value={contract.endsAt ? formatWhen(contract.endsAt, now) : "No end date"}
                    note={contract.endsAt ? formatCountdown(contract.endsAt, now) : "Reviewed rather than renewed"} />
                </Rows>
                <div style={{ marginTop: "var(--space-3)" }}>
                  <Button variant="outline" size="sm" onClick={() => onNavigate("/spend")}>Bills</Button>
                </div>
              </Card>
            ) : null}
          </div>

          <div>
            <Card title={"Jobs (" + jobs.length + ")"} note="Everything the house has asked them to do.">
              {jobs.length ? (
                <Rows>
                  {jobs.map((job) => (
                    <Row key={job.id}
                      title={<button type="button" className="hh-linkbtn" onClick={() => onNavigate("/upkeep/" + job.id)}>{job.title}</button>}
                      note={statusValue(JOB_STATUS, job.status).label + " · " + (job.scheduledAt ? formatWhen(job.scheduledAt, now) : "due " + formatWhen(job.dueAt, now)) + (job.costMinor ? " · " + formatPounds(job.costMinor) : job.quoteMinor ? " · " + formatPounds(job.quoteMinor) + " quoted" : "")}>
                      {job.overdue ? <Badge size="sm" variant="warning">{formatCountdown(job.dueAt, now)}</Badge> : null}
                      <Transitions transitions={jobTransitions(job, viewer).filter((t) => t.primary)} onRun={(t) => onJobTransition(job, t)} />
                    </Row>
                  ))}
                </Rows>
              ) : <p className="hh-footnote">No job on the record for them.</p>}
            </Card>

            <Card title={"Access they hold (" + grants.length + ")"} note="A provider's way in is a grant like any other, and it can be suspended from here."
              actions={<Button variant="outline" size="sm" onClick={() => onNavigate("/access")}>All access</Button>}>
              {grants.length ? (
                <Rows>
                  {grants.map((grant) => (
                    <Row key={grant.id} title={grant.label}
                      note={labelOf(ACCESS_KINDS, grant.kind) + " · " + grant.entryIds.map((id) => (entryById(data.entries, id) || {}).label).join(", ") + " · used " + formatCount(grant.uses) + " times, last " + formatWhen(grant.lastUsedAt, now)}>
                      <StatusBadge values={ACCESS_STATUS} value={grant.status} />
                      <Transitions transitions={accessTransitions(grant, viewer).filter((t) => t.primary)} onRun={(t) => onAccessTransition(grant, t)} />
                    </Row>
                  ))}
                </Rows>
              ) : <p className="hh-footnote">They have no code or key.</p>}
            </Card>
          </div>
        </div>
      </>
    );
  }

  Object.assign(window, { UpkeepScreen, JobScreen, ProvidersScreen, ProviderScreen });
})();
