/**
 * The questions Piggy offers before anyone has typed.
 *
 * These are chosen by what Piggy can actually answer where it is standing, not
 * by what the page is called. Interactive chat is given exactly one read tool —
 * `createInteractivePigTools` picks it from the record type, or from
 * `piggyPageGuide` for a route — so a starter the page's one tool cannot
 * ground is not merely unhelpful: it burns one of four turns and comes back
 * hedged. That is worse than offering nothing, so every line below was written
 * against the payload its tool returns and checked against the seeded book.
 *
 * Two consequences worth stating, because they look like omissions:
 *
 *  - Pages are grouped by tool, not by subject. /accounts and /facts get the
 *    same book questions as the dashboard because all three resolve to
 *    `pig_get_workspace_summary`. That tool now counts accounts and contacts,
 *    so a total is answerable from /accounts; what it still does not return is
 *    account ROWS, so "which account is at risk?" reads beautifully from that
 *    page and cannot be answered. Facts it does not see at all.
 *  - No starter names a horizon in days. `pig_get_calendar_ahead` takes
 *    `withinDays` and defaults to 30, and a question phrased around a quarter
 *    is only answered if the model chooses to pass the argument. Everything
 *    here returns something inside the default window.
 *
 * The voice is the desk's, not a chatbot's: a question with a decision behind
 * it beats a request for a summary, because the summary is already on screen.
 */
import { isPageContext, type PiggyPageRoute, type PiggyRecordType } from '@pig/core';
import type { PiggyChatContext } from '@/lib/piggy-chat';

// --------------------------------------------------------------- by tool

/** `pig_get_workspace_summary`: book margin, utilisation, open deal counts, worst idle blocks. */
const BOOK = [
  'Which block is losing us the most on hours nobody has bought?',
  'Is the book covering its cost once the idle hours are charged in?',
  'How much of the capacity we have bought is still unsold?',
  'Do we have enough open demand to cover the hours we have already bought?',
];

/** `pig_get_margin_summary`: totals plus the largest blocks by cost. */
const MARGIN = [
  'Which of the big blocks is dragging the book down?',
  'What is gross margin once the full cost of every commitment is counted?',
  'What are we clearing per allocated GPU-hour?',
  'How many hours have we bought this term and not sold?',
];

/** `pig_get_idle_capacity`: unsold blocks with their idle cost and break-even price. */
const IDLE = [
  'Which commitment is furthest from break-even?',
  'What would the remaining hours have to fetch to cover each block?',
  'What are the unsold hours costing us across the book?',
  'Which unsold block runs out of term first?',
];

/**
 * `pig_get_pipeline`, asked as a seller would ask it.
 *
 * There is no both-sides set any more: /demand and /supply are the only routes
 * this tool answers, and each one has a desk behind it. A neutral set existed
 * for /growth, which now resolves to the idle tool instead.
 */
const DEMAND_PIPELINE = [
  'Which open deal is worth the most, and when is it meant to land?',
  'How much of the pipeline has slipped past its expected close date?',
  'Which stage is holding the most value?',
  'What should we be chasing to close this month?',
];

/** The same tool, asked as a buyer would. */
const SUPPLY_PIPELINE = [
  'What capacity are we still negotiating, and at what target cost?',
  'Which supply deal would put the most GPUs on the book?',
  'Are we lining up more capacity than the demand side can absorb?',
  'What is stuck in diligence on the supply side?',
];

/** `pig_get_calendar_ahead`: the thirteen-kind projection, plus what is overdue. */
const DATES = [
  'What has already slipped and still needs chasing?',
  'What has to happen in the next month?',
  'Which holds expire before the deal behind them closes?',
  'How much pipeline is dated to close inside the window?',
];

/**
 * The calendar again, from /contracts. Narrower on purpose: the tool projects
 * dates, so a question about a term or a party has nothing to read.
 */
const CONTRACT_DATES = [
  'Which renewal or notice date lands next?',
  'What obligations fall due in the next month?',
  'What is overdue that we should have dealt with by now?',
];

// -------------------------------------------------------------- by record

/**
 * `pig_get_record` for each type, and for an account the lifecycle read as
 * well. Scoped to what that read returns and no further: a contact carries its
 * account row but none of the account's deals, and a supply deal's commitments
 * are only attached once the deal is live.
 */
const RECORD: Record<PiggyRecordType, string[]> = {
  account: [
    'Is this account getting less attention than it deserves?',
    'What is open with them, and what stage is it stuck at?',
    'What is blocking the next step here?',
    'How many hours have we actually sold this account?',
  ],
  contact: [
    'Who is this, and can they sign?',
    'What do we know about them, and how well sourced is it?',
    'What should I know before I contact them?',
  ],
  demand_deal: [
    'Are the hours behind this deal actually booked?',
    'How many GPU-hours does this take out of the book, and at what price?',
    'Is this going to close when it says it will?',
    'What paperwork is still missing before this can sign?',
  ],
  supply_deal: [
    'What is still outstanding before we can sign this block?',
    'How many GPU-hours would this add, and at what cost per hour?',
    'How long are we tied in for if we take it?',
    'What did technical and financial diligence conclude?',
  ],
  contract: [
    'What should we do about this renewal?',
    'When must we serve notice to stop this renewing itself?',
    'What obligations on this are still outstanding?',
    'What are we on the hook for if we do not use the capacity?',
  ],
  commitment: [
    'How much of this block is still unsold?',
    'What would the remaining hours have to fetch to cover it?',
    'How much term is left to sell the rest into?',
    'Who is holding hours on this block, and at what price?',
  ],
};

/**
 * Partial, and deliberately so — it mirrors the GUIDES table in
 * apps/piggy/src/page-routes.ts. A route added there without a guide falls back
 * to the workspace summary, and a route added here without an entry must fall
 * back to the questions that tool can answer. /learn is the live example: it
 * has no guide, so it is answered from the book like everything else.
 */
const PAGE: Partial<Record<PiggyPageRoute, string[]>> = {
  '/': BOOK,
  /*
   * Idle, not pipeline. /growth's guide names `pig_get_idle_capacity` — the
   * page's own figures are the idle ones — so a pipeline starter offered here
   * asks about stage counts and deal values that the one tool the model is
   * given cannot see. It would burn a turn and come back hedged.
   */
  '/growth': IDLE,
  '/margin': MARGIN,
  '/calendar': DATES,
  '/capacity': IDLE,
  '/demand': DEMAND_PIPELINE,
  '/supply': SUPPLY_PIPELINE,
  '/contracts': CONTRACT_DATES,
};

/**
 * Three or four openers for the context Piggy is in, most useful first.
 *
 * No context is the dashboard case by another name — `createInteractivePigTools`
 * resolves it to the same workspace summary — so it gets the same book
 * questions rather than a vaguer set of its own.
 */
export function piggySuggestions(context?: PiggyChatContext): string[] {
  const chosen = !context
    ? BOOK
    : isPageContext(context)
      ? (PAGE[context.route] ?? BOOK)
      : RECORD[context.type];
  // Copied, because these are module-level tables every caller shares and a
  // consumer that sorts or splices what it was handed would rewrite them.
  return [...chosen];
}

/** How many starters stay on offer once the conversation has begun. */
export const PIGGY_FOLLOW_UP_COUNT = 2;

/**
 * The starters worth keeping above the composer after the first turn.
 *
 * The full grid is a blank-state device and cannot survive the transcript — it
 * would push the answer off screen on a phone. A quiet pair can, and a second
 * question is the common case: today the openers vanish on the first send and
 * the user is left with an empty composer and no idea what else Piggy reads.
 *
 * `asked` is whatever the user has already sent, so a chip cannot offer back a
 * question that is already in the transcript above it. Compared loosely
 * because `send` trims before dispatching, so the stored turn rarely matches
 * the chip byte for byte.
 */
export function piggyFollowUps(
  context: PiggyChatContext | undefined,
  asked: readonly string[] = [],
): string[] {
  const spent = new Set(asked.map(normalise));
  return piggySuggestions(context)
    .filter((suggestion) => !spent.has(normalise(suggestion)))
    .slice(0, PIGGY_FOLLOW_UP_COUNT);
}

function normalise(text: string): string {
  return text.trim().toLowerCase();
}
