/**
 * The twelve verticals, as data.
 *
 * These are OUR proposals. Nothing here is Prime Intellect's roadmap, nothing
 * here describes a customer, and no company is named anywhere in this file.
 * `PROPOSAL_NOTICE` is rendered on every surface that shows a vertical, and it
 * is a constant rather than page copy so it cannot be dropped from one page and
 * kept on another.
 *
 * Each entry is an argument in four parts: the task an environment would run,
 * the reward in the buyer's own KPI, the counterweight that stops that reward
 * being farmed the crude way, and — where it applies — the caveat that says
 * where the argument stops being honest. An entry without a counterweight is
 * not a vertical, it is a slide.
 */

import type { Vertical } from '@/lib/demo-kit/types';

/** Rendered verbatim wherever a vertical appears. Never edit per page. */
export const PROPOSAL_NOTICE = 'Proposed by PIG-Demo';

export interface VerticalEntry {
  /** URL segment: `/verticals/<slug>`. */
  slug: string;
  title: string;
  /**
   * The registry's `Vertical` key, used to join a vertical to any demo built
   * for it. `null` where the contract has no key — see the note on
   * `semiconductor` at the bottom of this file.
   */
  key: Vertical | null;
  /** A lucide-react icon NAME. Resolved by the page, never imported here. */
  icon: string;
  /** Priority order across the whole lineup. 1 is the one we would build next. */
  rank: number;
  /** The job title that owns the budget for this. */
  persona: string;
  /** The question already in their head when they land. Written as they'd say it. */
  anxiety: string;
  /** The concrete unit of work one episode of the environment would cover. */
  task: string;
  /** What the reward pays for, stated in their KPI and not in ML vocabulary. */
  reward: string;
  /** What stops the reward being maximised the crude way. In genuine tension. */
  counterweight: string;
  /** Whether this is in the set we intend to build after the reference demo. */
  plannedForV1: boolean;
  /** Where the argument stops. Rendered as a standing warning, not a footnote. */
  caveat?: string;
}

export const VERTICALS: readonly VerticalEntry[] = [
  {
    slug: 'customer-support-resolution',
    title: 'Customer Support Resolution',
    key: 'support',
    icon: 'Headset',
    rank: 1,
    persona: 'VP of Customer Support',
    anxiety:
      'Deflection went up and CSAT went down in the same quarter. Nobody can tell me which of those the assistant caused.',
    task: 'Work one inbound ticket against a frozen snapshot of the help centre, the order record and the refund policy. Resolve it, or hand it to a human with the reason attached.',
    reward:
      'Pays for a first-contact resolution the customer does not reopen within seven days. One number, the one already on the support scorecard.',
    counterweight:
      'Refunding everything closes every ticket. So the reward subtracts for any resolution that granted more than the policy allowed, and for a handoff written to look like an answer. Escalating honestly outscores a generous close.',
    plannedForV1: true,
  },
  {
    slug: 'healthcare-denial-appeal',
    title: 'Healthcare RCM Denial Appeal',
    key: 'healthcare',
    icon: 'Stethoscope',
    rank: 2,
    persona: 'Revenue Cycle Director',
    anxiety:
      'We appeal a fraction of our denials because we cannot staff the rest. I do not know what that fraction costs us.',
    task: 'Given the denial code, the payer’s published medical policy and the chart excerpt, draft the appeal and cite the specific policy paragraph that supports it.',
    reward:
      'Pays overturned dollars per appeal, scored against the payer’s adjudicated outcome on the same claim.',
    counterweight:
      'Every cited policy line must appear verbatim in the attached policy, and every clinical fact must appear in the chart. One invented citation zeroes the appeal no matter how well the letter reads. A persuasive fabrication is the failure mode here, so the grader checks the sources before it reads the argument.',
    plannedForV1: true,
  },
  {
    slug: 'insurance-coverage-reserve',
    title: 'Insurance Coverage & Reserve',
    key: 'insurance',
    icon: 'ShieldCheck',
    rank: 3,
    persona: 'Chief Claims Officer',
    anxiety:
      'Adjusters set the initial reserve by feel. My development triangle is a monthly report on how expensive that feel is.',
    task: 'Read the first notice of loss, the policy form and the endorsements. Decide covered or not covered, name the clause that decides it, and set the initial reserve.',
    reward:
      'Pays on reserve accuracy: the gap between the number set on day one and the cost the claim actually closed at. The coverage call has to match the closed file.',
    counterweight:
      'Reserving high is accurate and expensive, so tied-up capital is charged against the score. Denying to protect the number is charged at the rate those denials were later overturned. The two pull in opposite directions on purpose.',
    plannedForV1: true,
  },
  {
    slug: 'financial-crime-alert-triage',
    title: 'Financial-Crime Alert Triage',
    key: 'financial-crime',
    icon: 'Siren',
    rank: 4,
    persona: 'BSA / AML Officer',
    anxiety:
      'Almost every alert my team reads is a false positive. The handful that are not is the entire conversation with my regulator.',
    task: 'Triage one transaction-monitoring alert against the customer’s KYC file and twelve months of account history. Close it, or escalate it for a suspicious-activity filing with a written narrative.',
    reward:
      'Pays for closing false positives, in analyst hours per thousand alerts. That is the number the operating budget is built on.',
    counterweight:
      'A missed escalation on an alert that later became a filed report costs more than every hour saved that month. The asymmetry lives in the reward weights, where you can read it and argue with it, instead of in a policy memo.',
    plannedForV1: true,
  },
  {
    slug: 'energy-day-ahead-bid',
    title: 'Energy Day-Ahead Bid',
    key: 'energy',
    icon: 'Zap',
    rank: 5,
    persona: 'Head of Power Trading',
    anxiety:
      'A model that backtests beautifully and then blows out a real-time position is worse than no model at all.',
    task: 'Submit a day-ahead bid curve for one asset across twenty-four hours, given the load forecast, the outage schedule and the historical basis.',
    reward:
      'Pays settled day-ahead revenue net of real-time, in dollars, at the clearing prices the market operator actually published for that day.',
    counterweight:
      'Imbalance charges and ramp limits settle against the same score, and any bid the market operator would have rejected settles at zero. A schedule the plant cannot physically deliver loses money in the grader exactly as it would on the desk.',
    plannedForV1: true,
  },
  {
    slug: 'logistics-load-and-reroute',
    title: 'Logistics Load & Reroute',
    key: 'logistics',
    icon: 'Truck',
    rank: 6,
    persona: 'VP of Transportation',
    anxiety:
      'Cost per load and on-time delivery move in opposite directions, and my planners choose between them every hour without writing down why.',
    task: 'Build the day’s load plan from the order book, then reroute it live when a driver runs out of hours and a dock appointment slips.',
    reward:
      'Pays landed cost per load and on-time-in-full against the receiver’s appointment window. Both, together, because either one alone is trivially gamed.',
    counterweight:
      'Hours-of-service, weight and appointment windows are hard constraints. A cheaper plan that puts a driver over their clock is not a cheaper plan; that leg scores zero and the saving disappears with it.',
    plannedForV1: true,
  },
  {
    slug: 'code-fix-the-test',
    title: 'Code Fix-the-Test',
    key: 'code',
    icon: 'Braces',
    rank: 7,
    persona: 'VP of Engineering',
    anxiety:
      'Every vendor shows me a pass rate on a public benchmark my team has never run on code my team has never seen.',
    task: 'Given a repository at a specific commit and one failing test, make that test pass.',
    reward:
      'The test suite is the grader. It pays 1 when the target test passes and everything that passed before still passes.',
    counterweight:
      'Editing the test, weakening its assertion or marking it skipped is caught by diffing the test files, and scores zero. This is the vertical where the grader argues back the least, which is exactly why it is the cheapest one to trust.',
    plannedForV1: true,
  },
  {
    slug: 'retail-markdown-cadence',
    title: 'Retail Markdown Cadence',
    key: 'retail',
    icon: 'Tag',
    rank: 8,
    persona: 'Chief Merchant',
    anxiety:
      'We run the same markdown ladder every season because relitigating it costs more than the margin it would save.',
    task: 'Set the weekly markdown for one style-colour across a season, given sell-through to date, units on hand and the weeks remaining.',
    reward:
      'Pays gross margin dollars at season end, computed on the sell-through curve that actually happened.',
    counterweight:
      'Whatever is left at the end is charged at its disposal cost, and the model cannot see the weeks it is pricing into. Holding price to protect margin ends the season owning the goods, and the score says so.',
    plannedForV1: false,
  },
  {
    slug: 'telecom-alarm-root-cause',
    title: 'Telecom Alarm → Root-Cause',
    key: 'telecom',
    icon: 'RadioTower',
    rank: 9,
    persona: 'SVP Network Operations',
    anxiety:
      'One fibre cut lights up thousands of alarms. My operations centre spends the first half of the outage deciding which one to read.',
    task: 'Correlate an alarm storm against the network topology and the change log, and name the single failing element.',
    reward:
      'Pays on time-to-identify, measured against the root cause the post-incident review recorded.',
    counterweight:
      'A confident wrong element costs the truck roll it triggers. Answering “insufficient evidence, here are the two candidates” scores higher than a fast wrong answer, which is the opposite of what a plain accuracy metric would teach.',
    plannedForV1: false,
  },
  {
    slug: 'data-column-split',
    title: 'Data Column Split',
    key: 'data',
    icon: 'Table2',
    rank: 10,
    persona: 'Chief Data Officer',
    anxiety:
      'A large part of my analytics backlog is a person reshaping a spreadsheet by hand and calling it a project.',
    task: 'Given one column of messy real values and a handful of worked examples, produce the transformation that splits or normalises the whole column.',
    reward:
      'Pays exact match on held-out rows the model never saw while it was writing the rule.',
    counterweight:
      'The rule is applied to those rows, not fitted to them, and a rule that special-cases individual values is penalised on length. Memorising the examples scores zero on the rows that pay.',
    plannedForV1: false,
  },
  {
    slug: 'legal-playbook-redline',
    title: 'Legal Playbook Redline',
    key: 'legal',
    icon: 'Scale',
    rank: 11,
    persona: 'General Counsel',
    anxiety:
      'First-pass review of a mutual NDA is not legal work, and it is still what my team does on a Thursday night.',
    task: 'Redline a counterparty contract against our own negotiation playbook and route each deviation to accept, negotiate, or escalate.',
    reward:
      'Pays for finding every clause the playbook flags and putting it in the right one of the three buckets. That is checkable against the playbook itself.',
    counterweight:
      'Escalating everything finds every clause and reviews nothing, so the escalation bucket has a budget and overspending it is penalised.',
    plannedForV1: false,
    caveat:
      'Finding the clause is checkable. Whether the replacement language is an acceptable redline is judgment, and grading judgment collapses to an LLM judge — the exact thing a verifiable reward is meant to replace. We would ship the detection half with a real verifier and say plainly that the drafting half is unverified. We would not put a judge behind a bar chart and call it a score.',
  },
  {
    slug: 'semiconductor-ppa-closure',
    title: 'Semiconductor PPA Closure',
    /*
     * No `Vertical` key exists for this one, and that is deliberate rather than
     * an oversight: it is on the page as the strongest form of the argument,
     * not as something we intend to build, so it is joined to no demo and never
     * appears as a gallery filter. See the contract note in the lane report.
     */
    key: null,
    icon: 'Cpu',
    rank: 12,
    persona: 'VP of Silicon Engineering',
    anxiety:
      'Timing closure is six weeks of a senior engineer’s life per tape-out, and we do it again next tape-out.',
    task: 'Adjust synthesis and place-and-route constraints on one block until it closes timing at the target frequency.',
    reward:
      'The signoff report is the reward: worst negative slack, total negative slack, area, leakage power. Numbers the tool prints. No rubric, no judge, no human in the scoring loop.',
    counterweight:
      'Hitting frequency by spending area or power is priced into the same objective, and a run that fails design-rule checks scores nothing however good its timing looks.',
    plannedForV1: false,
    caveat:
      'The most rigorous reward on this page and the worst demo on it. Signoff needs licensed EDA tools and hours of compute for a single rollout, and none of that fits in a browser tab. We are listing it because it is where the argument is strongest, and we are telling you we are not building it.',
  },
] as const;

/** Lookup by URL segment. Returns undefined for an unknown slug. */
export function verticalBySlug(slug: string | undefined): VerticalEntry | undefined {
  if (!slug) return undefined;
  return VERTICALS.find((v) => v.slug === slug);
}

/**
 * Lookup by the registry's `Vertical` key, so a demo can find its vertical.
 * `reference` intentionally matches nothing: the hello-world demo belongs to
 * no industry.
 */
export function verticalByKey(key: Vertical | undefined): VerticalEntry | undefined {
  if (!key) return undefined;
  return VERTICALS.find((v) => v.key === key);
}
