import type { Character, Encounter, Note, Quest } from '@/lib/schemas';
import { extractWikiLinks } from '@/lib/wikilinks';

export type Severity = 'info' | 'warn' | 'danger';

export type SuggestAction =
  | { type: 'goto'; to: string; params?: Record<string, string>; label: string }
  | { type: 'longRest'; characterId: string; label: string }
  | { type: 'createNote'; title: string; label: string };

export interface Suggestion {
  id: string;
  category: 'resources' | 'planning' | 'combat';
  severity: Severity;
  title: string;
  detail?: string;
  action?: SuggestAction;
}

/** Party readiness: downed, bloodied, and expended-resource nudges. */
export function resourceSuggestions(characters: Character[]): Suggestion[] {
  const pcs = characters.filter((c) => c.kind === 'pc');
  const out: Suggestion[] = [];

  for (const c of pcs) {
    if (c.hp.current <= 0) {
      out.push({
        id: `down-${c.id}`, category: 'resources', severity: 'danger',
        title: `${c.name} is down`, detail: 'At 0 HP.',
        action: { type: 'goto', to: '/characters/$characterId', params: { characterId: c.id }, label: 'Open sheet' },
      });
    } else if (c.hp.max > 0 && c.hp.current < c.hp.max * 0.5) {
      out.push({
        id: `bloodied-${c.id}`, category: 'resources', severity: 'warn',
        title: `${c.name} is bloodied`, detail: `${c.hp.current}/${c.hp.max} HP.`,
        action: { type: 'longRest', characterId: c.id, label: 'Long rest' },
      });
    }
    const spentSlots = c.spellcasting.slots.some((s) => s.current < s.max);
    if (spentSlots && c.hp.current > 0) {
      out.push({
        id: `slots-${c.id}`, category: 'resources', severity: 'info',
        title: `${c.name} has expended spell slots`,
        action: { type: 'longRest', characterId: c.id, label: 'Long rest' },
      });
    }
  }

  if (pcs.length > 0) {
    const totalFrac = pcs.reduce((s, c) => s + (c.hp.max > 0 ? c.hp.current / c.hp.max : 1), 0) / pcs.length;
    if (totalFrac < 0.5) {
      out.push({ id: 'party-low', category: 'resources', severity: 'warn', title: 'The party is running low', detail: 'Average HP is under half — a rest may be wise.' });
    }
  }
  return out;
}

/** Session-prep gaps: dangling wiki links, quest status, empty journal. */
export function planningSuggestions(notes: Note[], quests: Quest[]): Suggestion[] {
  const out: Suggestion[] = [];
  const titles = new Set(notes.map((n) => n.title.toLowerCase()));
  const dangling = new Set<string>();
  for (const n of notes) {
    for (const link of extractWikiLinks(n.body)) {
      if (!titles.has(link.toLowerCase())) dangling.add(link);
    }
  }
  for (const title of dangling) {
    out.push({
      id: `dangling-${title}`, category: 'planning', severity: 'info',
      title: `Missing note: “${title}”`, detail: 'A wiki link points to a note that does not exist yet.',
      action: { type: 'createNote', title, label: 'Create note' },
    });
  }

  const active = quests.filter((q) => q.status === 'active');
  if (active.length > 0) {
    out.push({
      id: 'active-quests', category: 'planning', severity: 'info',
      title: `${active.length} quest${active.length === 1 ? '' : 's'} in progress`,
      action: { type: 'goto', to: '/quests', label: 'Review quests' },
    });
  }
  if (notes.length === 0) {
    out.push({
      id: 'no-notes', category: 'planning', severity: 'info', title: 'No session notes yet',
      detail: 'Start a journal or lore wiki to keep track of the story.',
      action: { type: 'goto', to: '/notes', label: 'Open notes' },
    });
  }
  return out;
}

/** Live combat hints from the active encounter. */
export function combatSuggestions(encounter: Encounter | undefined): Suggestion[] {
  if (!encounter || encounter.status !== 'active') return [];
  const out: Suggestion[] = [];
  const current = encounter.combatants[encounter.turnIndex];
  if (current) {
    out.push({ id: 'turn', category: 'combat', severity: 'info', title: `Round ${encounter.round}: ${current.name}'s turn` });
  }
  const down = encounter.combatants.filter((c) => c.hp.current <= 0);
  if (down.length > 0) {
    out.push({
      id: 'down-combatants', category: 'combat', severity: 'warn',
      title: `${down.length} combatant${down.length === 1 ? '' : 's'} down`,
      detail: down.map((c) => c.name).join(', '),
      action: { type: 'goto', to: '/combat', label: 'Open combat' },
    });
  }
  return out;
}
