import { z } from 'zod';
import type { CampaignContext } from './context';

// ---- Session hooks ----

export const sessionHookSchema = z.object({
  hooks: z.array(z.object({
    title: z.string(),
    opening: z.string(),
    tension: z.string(),
  })).min(3).max(3),
});
export type SessionHook = z.infer<typeof sessionHookSchema>['hooks'][number];

export function buildSessionHookPrompt(ctx: CampaignContext): { system: string; user: string } {
  const system =
    `${ctx.systemConstraint}\n\n` +
    `You are a session-prep assistant for a ${ctx.systemLabel} game master. ` +
    `Generate exactly 3 distinct session opening hooks. Each hook needs a short title (3-6 words), ` +
    `an opening paragraph (2-3 sentences, suitable to read aloud or adapt at the table), and a one-sentence tension note ` +
    `(what makes this session interesting from a dramatic standpoint). ` +
    `Ground your hooks in the party's current situation — active quests, recent encounters, NPC threads. ` +
    `Vary the tone: one action-forward, one character/social, one mystery or twist.`;

  const partyLine = ctx.party.map((p) => `${p.name} (level ${p.level} ${p.className})`).join(', ') || 'the party';
  const user =
    `Campaign context:\n` +
    `Party: ${partyLine}\n` +
    `Active quests: ${ctx.questsSummary}\n` +
    `Notes/lore: ${ctx.notesSummary}\n` +
    (ctx.recentEncounters.length ? `Recent encounters: ${ctx.recentEncounters.slice(0, 3).map((e) => `${e.name} (${e.difficulty})`).join(', ')}\n` : '') +
    `\nGenerate 3 opening hooks for the next session.`;

  return { system, user };
}

const HOOK_TEMPLATES = [
  {
    title: 'Into the Unknown',
    opening: (q: string) =>
      `The road ahead leads deeper into uncertain territory. ${q ? `The party's current task — ${q} — draws them onward, ` : 'There\'s work to be done, '}but rumours along the way hint that things may be more complicated than expected.`,
    tension: 'An unexpected complication threatens to derail the party\'s immediate plans.',
  },
  {
    title: 'Old Debts',
    opening: () =>
      `A face from the past — an ally, a rival, or someone who simply remembers — reappears with news that changes the situation. They\'re not hostile, but they want something only the party can provide.`,
    tension: 'What they need may directly conflict with the party\'s current goals.',
  },
  {
    title: 'Crossed Paths',
    opening: () =>
      `Two separate threads tangle without warning: an urgent job lands at the worst possible moment, or unexpected help arrives from a quarter no one anticipated. The party has to decide quickly which thread to pull.`,
    tension: 'The party must prioritise between two competing urgent situations.',
  },
];

export function fallbackSessionHooks(ctx: CampaignContext): SessionHook[] {
  const quests = ctx.questsSummary !== 'No active quests.'
    ? ctx.questsSummary.replace(/^\d+ active: /, '').split('; ')
    : [];
  const firstQuest = quests[0] ?? '';
  return HOOK_TEMPLATES.map((t) => ({
    title: t.title,
    opening: t.opening(firstQuest),
    tension: t.tension,
  }));
}

// ---- NPC quick-gen ----

export const npcQuickSchema = z.object({
  name: z.string(),
  role: z.string(),
  motivation: z.string(),
  secret: z.string(),
  hook: z.string(),
});
export type NpcQuick = z.infer<typeof npcQuickSchema>;

export function buildNpcPrompt(
  ctx: Pick<CampaignContext, 'systemConstraint' | 'systemLabel' | 'questsSummary' | 'notesSummary'>,
  hint?: string,
): { system: string; user: string } {
  const system =
    `${ctx.systemConstraint}\n\n` +
    `You are an NPC generator for a ${ctx.systemLabel} game master. ` +
    `Generate one vivid, playable NPC with a name, a role (short phrase: "innkeeper", "mercenary captain", "hedge mage", etc.), ` +
    `a motivation (what they want right now — concrete, specific), a secret (one thing they would never willingly reveal), ` +
    `and a hook (one sentence: how you introduce or use them at the table). Keep all fields concise — the GM fills in the rest.`;

  const user =
    `Campaign notes: ${ctx.notesSummary}. Active quests: ${ctx.questsSummary}.` +
    (hint ? ` Requested type / context: ${hint}.` : '') +
    ` Generate one NPC.`;

  return { system, user };
}

const NPC_TEMPLATES: NpcQuick[] = [
  {
    name: 'Aldric Stonehaven',
    role: 'Inn owner',
    motivation: 'Keep his inn profitable and his guests\' troubles from spilling into his common room',
    secret: 'He owes a significant debt to a local thieves\' guild and occasionally passes along information about guests',
    hook: 'He nervously wipes the same glass over and over, eyes darting to the door — and quietly asks the party if they\'re looking for work',
  },
  {
    name: 'Sister Vera',
    role: 'Temple healer',
    motivation: 'Acquire a rare alchemical reagent to complete a cure for a sickness spreading in the lower city',
    secret: 'She was once a skilled thief; the temple doesn\'t know, and she prefers it stays that way',
    hook: 'She approaches the party after tending to their wounds, asking if they know anything about certain missing reagents',
  },
  {
    name: 'Captain Brenn Ashvale',
    role: 'Mercenary captain',
    motivation: 'Collect on a long-overdue contract before her company falls apart from unpaid wages',
    secret: 'The contract she\'s chasing was supposed to be straightforward — she\'s terrified of what she found in the ruins instead',
    hook: 'She\'s drinking alone in the corner, fully armoured and clearly not planning to sleep tonight',
  },
  {
    name: 'Mira of the Crossroads',
    role: 'Travelling merchant',
    motivation: 'Reach the next city before a rival merchant corners the market on her rare goods',
    secret: 'The "rare goods" she\'s carrying were lifted from a noble\'s estate under ambiguous circumstances',
    hook: 'She flagged down the party on the road, offering a discount on supplies in exchange for travelling together — she doesn\'t want to be alone',
  },
];

export function fallbackNpc(): NpcQuick {
  return NPC_TEMPLATES[Math.floor(Math.random() * NPC_TEMPLATES.length)]!;
}

// ---- Quest hook gen ----

export const questHookSchema = z.object({
  title: z.string(),
  description: z.string(),
  reward: z.string(),
  objectives: z.array(z.string()).min(1).max(4),
});
export type QuestHook = z.infer<typeof questHookSchema>;

export function buildQuestHookPrompt(ctx: CampaignContext): { system: string; user: string } {
  const system =
    `${ctx.systemConstraint}\n\n` +
    `You are a quest designer for a ${ctx.systemLabel} game master. ` +
    `Generate one compelling quest: a title (5 words or fewer), a 2–3 sentence description for the GM (not a read-aloud — a situation summary), ` +
    `a reward line (gold amount, item, or favour — be specific), and 2–4 concrete objectives as short imperative phrases.` +
    `The quest should be completable in one session. Connect it to the existing campaign notes or active quests if possible.`;

  const partyAvgLevel = ctx.partyLevels.length
    ? Math.round(ctx.partyLevels.reduce((a, b) => a + b, 0) / ctx.partyLevels.length)
    : 1;

  const user =
    `Party average level: ${partyAvgLevel}. Active quests: ${ctx.questsSummary}. Notes: ${ctx.notesSummary}.\n` +
    `Generate one new side quest appropriate for this party.`;

  return { system, user };
}

const QUEST_TEMPLATES: QuestHook[] = [
  {
    title: 'The Missing Merchant',
    description: 'A local merchant departed three days ago for a nearby town and never arrived. His family has received no word and fears the worst. The road is not normally dangerous, which makes the disappearance all the stranger.',
    reward: '150 gp and the merchant\'s gratitude (discount on future trade goods)',
    objectives: ['Investigate the merchant\'s last known stop', 'Search the road between settlements', 'Return the merchant safely — or discover what happened'],
  },
  {
    title: 'Trouble at the Mill',
    description: 'The grain mill that feeds the town has fallen silent. The miller and his apprentices vanished two nights ago. Locals report strange lights and sounds from the millpond after dark — something is in the water.',
    reward: '100 gp from the town council and free lodging for a month',
    objectives: ['Investigate the mill and surrounding area', 'Discover what is lurking in the millpond', 'Ensure the mill is safe to operate again'],
  },
  {
    title: 'A Stolen Heirloom',
    description: 'A noble family\'s ancestral signet ring was taken by a skilled thief during a dinner party. Every guest is a suspect. The family will pay handsomely to recover it quietly — and even more to know who took it.',
    reward: '200 gp and a favour from a noble house',
    objectives: ['Question the guests and staff', 'Identify the thief through investigation', 'Recover the signet ring'],
  },
  {
    title: 'Old Ruins, New Danger',
    description: 'Explorers opened a sealed chamber in nearby ruins and haven\'t returned. Their employer wants to know what happened and whether the contents of the chamber are still accessible. The ruins were sealed for a reason.',
    reward: 'A share of whatever the explorers found, plus 100 gp per party member',
    objectives: ['Enter the ruins through the explorers\' route', 'Locate the sealed chamber', 'Deal with whatever the explorers disturbed', 'Report back to the employer'],
  },
];

export function fallbackQuestHook(): QuestHook {
  return QUEST_TEMPLATES[Math.floor(Math.random() * QUEST_TEMPLATES.length)]!;
}
