/* Claim — assessment. The reconciliation between what the customer claims and
   what we owe is the anchor of this screen; everything else is a rail.
   Commit model: STAGED. Every control here is a form field: the three
   adjustments apply on Save assessment, Save and Cancel are disabled until the
   form is dirty and valid, and Save shows pending. The header's transitions are
   not controls on this form — they navigate, or they open a dialog carrying its
   own commit model.
   Data state: populated (a claim that does not exist is a branch in App). */
(() => {
  const {
    Button, Input, Card, CardHeader, CardTitle, CardDescription, CardPanel, CardFooter,
    Alert, AlertTitle, AlertDescription, Badge, Separator,
  } = window.OriginDesignSystem_7c998b;

  const sdr = (n) => new Intl.NumberFormat("en-US", { maximumFractionDigits: 0 }).format(n) + " SDR";

  /* The transitions offered on a claim, derived from its status — the same
     function for all three claim screens. */
  function ClaimHeaderActions({ claim, view, onNavigate, onTransition }) {
    const transitions = claimTransitions(claim);
    const missing = CLAIM_FLAGS.missingMandatory(claim);
    const recovery = claim.recoveryId;
    return (
      <>
        {transitions.map((t) => {
          if (t.id === "record_decision") {
            /* One entry point per action per screen: on the decision screen the
               form below is the entry point, so the header does not repeat it. */
            if (view === "decision") return null;
            const blocked = missing.length > 0;
            const button = <Button size="sm" disabled={blocked} onClick={() => onNavigate("/claims/" + claim.id + "/decision")}>{t.label}</Button>;
            return blocked
              ? <FloatingTip key={t.id} side="bottom" label={"Waiting on evidence — " + missing.map((m) => labelOf(DOCUMENT_TYPES, m).toLowerCase()).join(", ")}>{button}</FloatingTip>
              : <React.Fragment key={t.id}>{button}</React.Fragment>;
          }
          if (t.id === "schedule_payment") {
            return <Button key={t.id} variant="outline" size="sm" onClick={() => onNavigate("/payments")}>Open on the payments desk</Button>;
          }
          return (
            <Button key={t.id} variant="outline" size="sm" onClick={() => onTransition(claim, t)}>{t.label}</Button>
          );
        })}
        {recovery ? <Button variant="ghost" size="sm" onClick={() => onNavigate("/recovery/" + recovery)}>Recovery file<Icon name="arrow-right" /></Button> : null}
      </>
    );
  }

  /* Identity, clock, cargo and the three views — identical on all three claim
     screens, so only the surface below changes. */
  function ClaimHeader({ claim, now, view, onNavigate, onTransition }) {
    return (
      <RecordHead
        claim={claim}
        now={now}
        crumb={<Crumbs path={CLAIM_VIEWS.find((v) => v.value === view).route.path} params={{ id: claim.id }} labels={{ "/claims/:id": claim.id }} />}
        actions={<ClaimHeaderActions claim={claim} view={view} onNavigate={onNavigate} onTransition={onTransition} />}
      >
        <ClaimTabs claim={claim} view={view} onNavigate={onNavigate} />
      </RecordHead>
    );
  }

  function LedgerRow({ label, hint, value, className }) {
    return (
      <div className={"cd-lg__row" + (className ? " " + className : "")}>
        <span className="cd-lg__label">{label}{hint ? <span className="cd-lg__hint">{hint}</span> : null}</span>
        <span className="cd-lg__value">{value}</span>
      </div>
    );
  }

  function AdjustmentRow({ id, label, hint, value, error, onChange }) {
    return (
      <div className="cd-lg__row cd-lg__row--input">
        <span className="cd-lg__label">
          <label htmlFor={id}>{label}</label>
          <span className="cd-lg__hint">{error ? <span style={{ color: "var(--destructive-foreground)" }}>{error}</span> : hint}</span>
        </span>
        <span className="cd-lg__value">
          <Input id={id} size="sm" inputMode="decimal" startAddon="−  $" wrapperClassName="cd-lg__input" value={value} invalid={!!error} onChange={(e) => onChange(e.target.value)} />
        </span>
      </div>
    );
  }

  function ProportionBars({ ledger }) {
    const max = Math.max(ledger.claimed, ledger.assessed, ledger.cap.cents);
    const pct = (n) => Math.max(0.5, (n / max) * 100) + "%";
    const rows = [
      { label: "Claimed", value: ledger.claimed, strong: false },
      { label: "Assessed", value: ledger.assessed, strong: false },
      { label: "Payable", value: ledger.payable, strong: true },
    ];
    return (
      <div className="cd-bars">
        {rows.map((row) => (
          <div className="cd-bars__row" key={row.label}>
            <span className="cd-muted">{row.label}</span>
            <span className="cd-bars__track">
              <span className={"cd-bars__fill" + (row.strong ? " cd-bars__fill--strong" : "")} style={{ width: pct(row.value) }} />
              <span className="cd-bars__cap" style={{ left: pct(ledger.cap.cents) }} title={"Liability cap " + formatMoney(ledger.cap.cents)} />
            </span>
            <span className="cd-bars__value">{formatMoney(row.value)}</span>
          </div>
        ))}
        <p className="cd-note">The red line is the liability cap at {formatMoney(ledger.cap.cents)}. Payable can touch it, never cross it.</p>
      </div>
    );
  }

  function ClaimScreen({ claim, data, now, onNavigate, onTransition, onSaveAssessment, pushToast }) {
    const blank = { depreciation: "", salvage: "", deductible: "" };
    const fromClaim = (c) => (c.assessment
      ? { depreciation: moneyInputValue(c.assessment.depreciationCents), salvage: moneyInputValue(c.assessment.salvageCents), deductible: moneyInputValue(c.assessment.deductibleCents) }
      : blank);
    const [draft, setDraft] = React.useState(() => fromClaim(claim));
    const [touched, setTouched] = React.useState({});
    const [saving, setSaving] = React.useState(false);
    React.useEffect(() => { setDraft(fromClaim(claim)); setTouched({}); }, [claim]);

    const saved = fromClaim(claim);
    const dirty = ["depreciation", "salvage", "deductible"].some((k) => draft[k] !== saved[k]);
    const cents = (key) => (draft[key].trim() === "" ? 0 : parseMoney(draft[key]));
    const fieldError = (key) => {
      const value = cents(key);
      if (isNaN(value) || value < 0) return "Enter an amount in dollars, or 0.";
      return null;
    };
    const drafted = { depreciationCents: cents("depreciation"), salvageCents: cents("salvage"), deductibleCents: cents("deductible") };
    const anyFieldError = ["depreciation", "salvage", "deductible"].some((k) => fieldError(k));
    const ledger = anyFieldError ? assess(claim, claim.assessment) : assess(claim, drafted);
    const overClaimed = !anyFieldError && ledger.assessed !== null && ledger.assessed < 0;
    const valid = !anyFieldError && !overClaimed;

    const save = () => {
      setSaving(true);
      window.setTimeout(() => {
        setSaving(false);
        onSaveAssessment(claim, drafted);
        pushToast({ variant: "success", title: "Assessment saved", description: claim.id + " · payable " + formatMoney(Math.min(claim.claimedCents - (drafted.depreciationCents + drafted.salvageCents + drafted.deductibleCents), liabilityCap(claim).cents)) });
      }, 500);
    };

    const cap = liabilityCap(claim);
    const capHint = "Higher of " + formatCount(claim.packages) + " packages × " + CLAIM_POLICY.packageLimitSdr + " SDR (" + sdr(cap.byPackageSdr) + ") and " + formatCount(claim.weightKg) + " kg × " + CLAIM_POLICY.weightLimitSdrPerKg + " SDR (" + sdr(cap.byWeightSdr) + "), at " + CLAIM_POLICY.sdrUsdRate + " USD/SDR";
    const missing = CLAIM_FLAGS.missingMandatory(claim);
    const recovery = recoveryForClaim(data.recoveries, claim);

    return (
      <div className="cd-page">
        <ClaimHeader claim={claim} now={now} view="assessment" onNavigate={onNavigate} onTransition={onTransition} />

        <div className="cd-split">
          <div className="cd-col">
            <Card className="cd-card">
              <CardHeader>
                <CardTitle>What we owe</CardTitle>
                <CardDescription>
                  The customer claims {formatMoney(claim.claimedCents)}. Everything below it is an adjustment you can defend in writing, and the cap is the last word.
                </CardDescription>
              </CardHeader>
              <CardPanel>
                <div className="cd-lg">
                  <LedgerRow label="Claimed by the customer" hint={"Commercial invoice value · " + claim.commodity} value={formatMoney(claim.claimedCents)} />
                  <AdjustmentRow id="cd-dep" label="Depreciation and betterment" hint="Age and condition of the goods at shipment" value={draft.depreciation} error={touched.depreciation ? fieldError("depreciation") : null} onChange={(v) => { setTouched((t) => Object.assign({}, t, { depreciation: true })); setDraft((d) => Object.assign({}, d, { depreciation: v })); }} />
                  <AdjustmentRow id="cd-sal" label="Salvage recovered" hint="Proceeds the consignee realised on the damaged goods" value={draft.salvage} error={touched.salvage ? fieldError("salvage") : null} onChange={(v) => { setTouched((t) => Object.assign({}, t, { salvage: true })); setDraft((d) => Object.assign({}, d, { salvage: v })); }} />
                  <AdjustmentRow id="cd-ded" label="Deductible" hint="Bill of lading clause 14" value={draft.deductible} error={touched.deductible ? fieldError("deductible") : null} onChange={(v) => { setTouched((t) => Object.assign({}, t, { deductible: true })); setDraft((d) => Object.assign({}, d, { deductible: v })); }} />
                  {ledger.assessed === null ? (
                    <LedgerRow className="cd-lg__row--sub" label="Assessed liability" hint="Enter the adjustments above to assess this claim" value={<span className="cd-muted">Not assessed</span>} />
                  ) : (
                    <>
                      <LedgerRow className="cd-lg__row--sub" label="Assessed liability" hint={"Claimed less " + formatMoney(ledger.deductions) + " of adjustments"} value={formatMoney(ledger.assessed)} />
                      <LedgerRow className="cd-lg__row--cap" label="Liability cap, bill of lading" hint={capHint} value={formatMoney(ledger.cap.cents)} />
                      <LedgerRow
                        className="cd-lg__row--payable"
                        label={<span style={{ fontWeight: "var(--font-weight-medium)" }}>Payable today</span>}
                        hint={ledger.capBinds
                          ? "The cap binds. " + formatMoney(ledger.cappedAway) + " of assessed liability is not payable, on the " + ledger.cap.basis + " limitation."
                          : "Below the cap by " + formatMoney(ledger.cap.cents - ledger.assessed) + ", so the assessment stands."}
                        value={formatMoney(ledger.payable)}
                      />
                    </>
                  )}
                </div>
                {overClaimed ? (
                  <Alert variant="error" style={{ marginTop: "var(--space-4)" }}>
                    <AlertTitle>The adjustments exceed the claim</AlertTitle>
                    <AlertDescription>{formatMoney(drafted.depreciationCents + drafted.salvageCents + drafted.deductibleCents)} of adjustments against {formatMoney(claim.claimedCents)} claimed leaves nothing to assess. Reduce one of them.</AlertDescription>
                  </Alert>
                ) : null}
                {ledger.assessed !== null && !overClaimed ? <div style={{ marginTop: "var(--space-6)" }}><ProportionBars ledger={ledger} /></div> : null}
              </CardPanel>
              <CardFooter className="cd-form-foot">
                <span className="cd-form-foot__note">
                  {claim.assessment
                    ? "Last assessed by " + claim.assessment.assessedBy + " on " + formatAbsolute(claim.assessment.assessedAt) + "."
                    : "This claim has not been assessed yet."}
                  {CLAIM_FLAGS.needsSignoff(ledger.payable || 0) ? " Above your " + formatMoney(CLAIM_POLICY.authorityLimitCents) + " authority, so the decision needs " + CLAIMS_MANAGER.name + "'s sign-off." : ""}
                </span>
                {dirty ? <Button variant="outline" onClick={() => { setDraft(saved); setTouched({}); }}>Cancel</Button> : null}
                <Button disabled={!dirty || !valid} loading={saving} onClick={save}>Save assessment</Button>
              </CardFooter>
            </Card>
          </div>

          <div className="cd-col cd-col--tight">
            <Card>
              <CardHeader>
                <CardTitle>Cargo and carriage</CardTitle>
                <CardDescription>From the bill of lading and the delivery receipt.</CardDescription>
              </CardHeader>
              <CardPanel>
                <dl className="cd-defs">
                  <dt>Bill of lading</dt><dd className="cd-code">{claim.bl}</dd>
                  <dt>Container</dt><dd className="cd-code">{claim.container}</dd>
                  <dt>Vessel and voyage</dt><dd>{claim.vessel} {claim.voyage}</dd>
                  <dt>Loaded at</dt><dd>{claim.pol}</dd>
                  <dt>Discharged at</dt><dd>{claim.pod}</dd>
                  <dt>Commodity</dt><dd>{claim.commodity}</dd>
                  <dt>Packages</dt><dd>{formatCount(claim.packages)}</dd>
                  <dt>Gross weight</dt><dd>{formatCount(claim.weightKg)} kg</dd>
                  <dt>Delivered</dt><dd>{formatAbsolute(claim.deliveredAt)}</dd>
                  <dt>Claim filed</dt><dd>{formatAbsolute(claim.claimedAt)}</dd>
                </dl>
              </CardPanel>
            </Card>

            <Card>
              <CardHeader>
                <CardTitle>Evidence</CardTitle>
                <CardDescription>
                  {missing.length === 0
                    ? "All " + MANDATORY_DOCUMENT_TYPES.length + " mandatory documents are on file."
                    : (MANDATORY_DOCUMENT_TYPES.length - missing.length) + " of " + MANDATORY_DOCUMENT_TYPES.length + " mandatory documents on file."}
                </CardDescription>
              </CardHeader>
              <CardPanel>
                <div className="cd-col cd-col--tight">
                  <DocumentPips documents={claim.documents} />
                  {missing.length ? (
                    <p className="cd-note">Missing: {missing.map((m) => labelOf(DOCUMENT_TYPES, m)).join(", ")}. You cannot record a decision until they are on file.</p>
                  ) : (
                    <p className="cd-note">Nothing outstanding — the file can be decided. {DOCUMENT_TYPES.length} checklist rows, {MANDATORY_DOCUMENT_TYPES.length} of them mandatory.</p>
                  )}
                </div>
              </CardPanel>
              <CardFooter>
                <Button variant="ghost" size="sm" onClick={() => onNavigate("/claims/" + claim.id + "/evidence")}>Open evidence<Icon name="arrow-right" /></Button>
              </CardFooter>
            </Card>

            {claim.notes && claim.notes.length ? (
              <Card>
                <CardHeader>
                  <CardTitle>File notes</CardTitle>
                  <CardDescription>{formatPlural(claim.notes.length, "entry", "entries")}, newest first.</CardDescription>
                </CardHeader>
                <CardPanel>
                  <div className="cd-log">
                    {claim.notes.slice().sort((a, b) => b.at - a.at).map((note) => (
                      <div className="cd-log__item" key={note.at}>
                        <span className="cd-log__who">{note.who}</span>
                        <span className="cd-log__when" title={formatAbsolute(note.at)}>{formatWhen(note.at, now)}</span>
                        <span className="cd-log__text">{note.text}</span>
                      </div>
                    ))}
                  </div>
                </CardPanel>
              </Card>
            ) : null}

            {recovery ? (
              <Card>
                <CardHeader>
                  <CardTitle>Recovery</CardTitle>
                  <CardDescription>{recovery.counterparty.name} · {labelOf(COUNTERPARTY_KINDS, recovery.counterparty.kind)}</CardDescription>
                </CardHeader>
                <CardPanel>
                  <dl className="cd-defs">
                    <dt>Sought</dt><dd className="cd-amount">{formatMoney(recovery.soughtCents)}</dd>
                    <dt>Recovered</dt><dd className="cd-amount">{formatMoney(recovery.recoveredCents)}</dd>
                    <dt>Status</dt><dd><StatusBadge values={RECOVERY_STATUS} value={recovery.status} /></dd>
                  </dl>
                </CardPanel>
                <CardFooter>
                  <Button variant="ghost" size="sm" onClick={() => onNavigate("/recovery/" + recovery.id)}>Open the recovery file<Icon name="arrow-right" /></Button>
                </CardFooter>
              </Card>
            ) : null}
          </div>
        </div>
      </div>
    );
  }

  Object.assign(window, { ClaimScreen, ClaimHeader, ClaimHeaderActions, LedgerRow, ProportionBars });
})();
