// Canonical action + writing-style lists shared by the toolbar, popup,
// context menus, and result modal. Values must stay in sync with the system
// prompts in the background worker.

// 'fix' is the user-facing id emitted by the context menu and popup; the
// background normalizes it to the 'grammar' prompt.
export const ACTIONS = ['fix', 'rephrase', 'shorten', 'expand', 'explain', 'prompt'] as const;
export type ActionId = (typeof ACTIONS)[number];

export const ACTION_LABELS: Record<ActionId, string> = {
  fix: 'Fix Grammar',
  rephrase: 'Rephrase',
  shorten: 'Shorten',
  expand: 'Expand',
  explain: 'Explain',
  prompt: 'Make Prompt',
};

// Full list, including the 'Default' pseudo-style (= no style modifier).
export const WRITING_STYLES = ['Default', 'Formal', 'Casual', 'Academic', 'Creative', 'Concise'] as const;
export type WritingStyle = (typeof WRITING_STYLES)[number];

// Context menus omit 'Default' — the parent action item already covers it.
export const CONTEXT_MENU_STYLES = WRITING_STYLES.filter((s) => s !== 'Default');

// ─── Prompt Builder parameters (the 'prompt' action) ─────────────────────────
// 'Auto' always means "let the prompt engineer decide from the input".

// Structural prompt-engineering patterns, drawn from docs/prompting_style.md.
// Stable ids (not labels) are stored/persisted so relabeling stays free.
// 'auto' has no group — it renders first, outside the optgroups.
export interface PromptPatternDef {
  id: string;
  label: string;
  group: 'Direct' | 'Reasoning' | 'Agentic';
  hint: string; // one line: when to use it + its cost
}

export const PROMPT_PATTERNS: PromptPatternDef[] = [
  { id: 'auto', label: 'Auto', group: 'Direct', hint: 'Let the prompt engineer pick the cheapest pattern that fits the input.' },
  { id: 'zero-shot', label: 'Zero-shot Instruction', group: 'Direct', hint: 'Direct imperative instructions, no scaffolding. Lowest cost — simple, single-step tasks.' },
  { id: 'role', label: 'Role Conditioning', group: 'Direct', hint: 'Role/domain/invariants block; steadies tone and expertise across a longer chat.' },
  { id: 'few-shot', label: 'Few-shot Examples', group: 'Direct', hint: 'Shows 1-2 example input→output pairs. Best for consistent formatting or extraction.' },
  { id: 'structured', label: 'Structured Sections', group: 'Direct', hint: 'Labeled Context/Task/Constraints/Output. Clearer for multi-constraint requests.' },
  { id: 'contract', label: 'Output Contract', group: 'Direct', hint: 'Pins an exact output schema. Best when downstream code parses the result.' },
  { id: 'cot', label: 'Chain-of-Thought', group: 'Reasoning', hint: 'Reasons step by step before answering. For math, logic, multi-constraint problems.' },
  { id: 'plan-solve', label: 'Plan-and-Solve', group: 'Reasoning', hint: 'Plans first, then executes in order. For open-ended design or multi-part tasks.' },
  { id: 'tot', label: 'Tree-of-Thoughts', group: 'Reasoning', hint: 'Scores multiple candidate approaches and keeps the best. High cost — hard planning/refactors.' },
  { id: 'react', label: 'ReAct (tools)', group: 'Agentic', hint: 'Thought/Action/Observation tool loop for a tool-capable agent, not a plain chat.' },
  { id: 'pev', label: 'Plan-Execute-Verify', group: 'Agentic', hint: 'Task DAG with per-step verification, for a tool-capable agent on multi-step builds.' },
  { id: 'gauntlet', label: 'Gauntlet (Builder–Judge)', group: 'Agentic', hint: 'Builder vs. fresh-context judge on a named standard, for a tool-capable agent. Very high cost.' },
];

// Legacy label -> new pattern id (storage persists across versions).
const LEGACY_PATTERN_IDS: Record<string, string> = {
  Auto: 'auto',
  Instructional: 'zero-shot',
  'Role-play': 'role',
  'Step-by-step': 'cot',
  'Few-shot': 'few-shot',
  Structured: 'structured',
};

// Resolves a stored Prompt Builder pattern selection into a valid
// PROMPT_PATTERNS id: `pattern` if already a known id, else the legacy
// `promptStyle` label mapped through LEGACY_PATTERN_IDS, else 'auto'.
export function resolvePromptPattern(pattern?: string, legacyStyle?: string): string {
  if (pattern && PROMPT_PATTERNS.some((p) => p.id === pattern)) return pattern;
  if (legacyStyle && LEGACY_PATTERN_IDS[legacyStyle]) return LEGACY_PATTERN_IDS[legacyStyle];
  return 'auto';
}

// 'Custom…' switches the popup to a free-text persona field.
export const PROMPT_PERSONAS = [
  'Auto',
  'None',
  'Expert Developer',
  'Copywriter',
  'Teacher',
  'Data Analyst',
  'Business Consultant',
  'Researcher',
  'Custom…',
] as const;
export type PromptPersona = (typeof PROMPT_PERSONAS)[number];

export const PROMPT_FORMATS = ['Auto', 'Plain text', 'Markdown', 'Bulleted list', 'Numbered steps', 'JSON', 'Table'] as const;
export type PromptFormat = (typeof PROMPT_FORMATS)[number];

// 'Custom…' means "use the free-text persona"; an empty custom text falls
// back to Auto. Shared by the popup and the background (which resolves saved
// Prompt Builder settings for toolbar/context-menu prompt requests).
export function resolvePromptPersona(persona?: string, customPersona?: string): string | undefined {
  if (persona === 'Custom…') return customPersona?.trim() || 'Auto';
  return persona;
}

// Minimum selection length (chars, after trim) before the floating toolbar
// appears. Kept deliberately above 1-2 chars so accidental double-click
// selections don't trigger the UI.
export const MIN_SELECTION_LENGTH = 10;

// ─── Context-menu registry ────────────────────────────────────────────────────
// Declarative id -> {action, style} mapping. Replaces the old split('-')
// parsing of menuItemId, which only worked because no action or style name
// contained a hyphen. Order matters: each parent precedes its children so
// chrome.contextMenus.create never sees an unknown parentId.

export interface ContextMenuEntry {
  id: string;
  action: ActionId;
  style: WritingStyle;
  // 'Default' entries are top-level parents; styled entries nest under them.
  parentId?: string;
  title: string;
}

export const CONTEXT_MENU_ENTRIES: ContextMenuEntry[] = ACTIONS.flatMap((action) => [
  {
    id: `lexai-${action}`,
    action,
    style: 'Default' as WritingStyle,
    title: `⚡ LexAI: ${ACTION_LABELS[action]}`,
  },
  // 'prompt' opens the Prompt Builder dialog in the page, which has its own
  // parameters — writing-style children don't apply to it.
  ...(action === 'prompt'
    ? []
    : CONTEXT_MENU_STYLES.map((style) => ({
        id: `lexai-${action}-${style.toLowerCase()}`,
        action,
        style,
        parentId: `lexai-${action}`,
        title: style as string,
      }))),
]);

export function findContextMenuEntry(menuItemId: string): ContextMenuEntry | undefined {
  return CONTEXT_MENU_ENTRIES.find((e) => e.id === menuItemId);
}
