import { z } from 'zod';
import type { Character } from '@/lib/schemas';
import type { CampaignContext, CreatureCandidate } from './context';

export const balanceSuggestionSchema = z.object({
  reasoning: z.string(),
  add: z.array(z.object({
    name: z.string(),
    count: z.number().int().min(1).max(8),
    ref: z.string().optional(),
  })),
  targetDifficulty: z.string(),
});
export type BalanceSuggestion = z.infer<typeof balanceSuggestionSchema>;

function partyLine(ctx: CampaignContext): string {
  return ctx.party.map((p) => `${p.name} (level ${p.level} ${p.className})`).join(', ') || 'no PCs recorded';
}

/**
 * Prompt for rebalancing the current encounter. The system message leads with the
 * grounding constraint and restricts choices to the provided candidate list.
 */
export function buildBalancePrompt(
  ctx: CampaignContext,
  current: { difficulty: string; targetDifficulty: string; candidates: CreatureCandidate[] },
): { system: string; user: string } {
  const system =
    `${ctx.systemConstraint}\n\n` +
    `You are an encounter-balancing assistant for a ${ctx.systemLabel} game master. ` +
    `Recommend which creatures to ADD to the current encounter to bring it to roughly "${current.targetDifficulty}" difficulty. ` +
    `You MUST choose only from the provided candidate creatures (by exact name). Do not invent creatures or use any from another system. ` +
    `Prefer 1–3 distinct creatures with sensible counts. Keep the reasoning to one or two sentences.`;

  const candidateList = current.candidates
    .map((c) => `- ${c.name} (rating ${c.rating}${c.hp ? `, hp ${c.hp}` : ''}${c.ac ? `, ac ${c.ac}` : ''})`)
    .join('\n');

  const user =
    `Party: ${partyLine(ctx)}.\n` +
    `Current encounter difficulty: ${current.difficulty}.\n` +
    `Target difficulty: ${current.targetDifficulty}.\n\n` +
    `Candidate creatures (choose only from these):\n${candidateList}\n\n` +
    `Respond with the creatures to add (name + count), a short reasoning, and the targetDifficulty.`;

  return { system, user };
}

// ---------------- Level-up advisor ----------------

export const buildRoutesSchema = z.object({
  routes: z.array(z.object({
    title: z.string(),
    summary: z.string(),
    playstyle: z.string(),
  })).min(3).max(4),
});
export type BuildRoute = z.infer<typeof buildRoutesSchema>['routes'][number];

export const buildStepsSchema = z.object({
  steps: z.array(z.object({ label: z.string(), detail: z.string() })).min(1),
});
export type BuildStep = z.infer<typeof buildStepsSchema>['steps'][number];

function charLine(c: Character): string {
  const abilities = Object.entries(c.abilities).map(([k, v]) => `${k.toUpperCase()} ${v}`).join(', ');
  return `${c.name}, a level ${c.level} ${c.className || 'adventurer'} (${abilities})`;
}

export function buildLevelUpRoutesPrompt(ctx: CampaignContext, c: Character, nextLevel: number): { system: string; user: string } {
  const system =
    `${ctx.systemConstraint}\n\n` +
    `You are a character-building advisor for ${ctx.systemLabel}. Propose 4 distinct build routes for the next level. ` +
    `Each route needs a short title, a one-sentence summary, and a one-phrase playstyle. ` +
    `Use only ${ctx.systemLabel} mechanics, feats, and class options — never another system's.`;
  const user = `Character: ${charLine(c)}. Leveling up to ${nextLevel}. Suggest 4 build routes.`;
  return { system, user };
}

export function buildLevelUpStepsPrompt(ctx: CampaignContext, c: Character, nextLevel: number, chosenRoute: string): { system: string; user: string } {
  const system =
    `${ctx.systemConstraint}\n\n` +
    `You are a character-building advisor for ${ctx.systemLabel}. Give concrete, ordered steps to pursue the chosen build route at this level. ` +
    `Each step has a short label and a one-sentence detail. Reference only ${ctx.systemLabel} options (feats, ability boosts, spells, skill increases as appropriate). Keep to 3–5 steps.`;
  const user = `Character: ${charLine(c)}. Leveling up to ${nextLevel}. Chosen route: "${chosenRoute}". How should they achieve it?`;
  return { system, user };
}
