import * as vscode from 'vscode';
import type { LexAIConfig, PromptParams } from '@lib/types';
import { PROVIDER_SPECS, providerLabel } from '@lib/providers';
import type { WritingStyle } from '@lib/actions';
import {
  PROMPT_FORMATS,
  PROMPT_PATTERNS,
  PROMPT_PERSONAS,
  WRITING_STYLES,
  resolvePromptPattern,
  resolvePromptPersona,
} from '@lib/actions';

export const SECRET_API_KEY = 'lexai.apiKey';
export const GLOBAL_KEY_PROVIDER = 'lexai.keyProvider';

export interface VsCodeLexAISettings {
  provider: string;
  model: string;
  writingStyle: WritingStyle;
  promptPattern: string;
  promptPersona: string;
  customPersona: string;
  promptFormat: string;
  promptModel: string;
}

function pickEnum<T extends string>(value: string | undefined, allowed: readonly T[], fallback: T): T {
  return value && (allowed as readonly string[]).includes(value) ? (value as T) : fallback;
}

export function readSettings(): VsCodeLexAISettings {
  const cfg = vscode.workspace.getConfiguration('lexai');
  const provider = cfg.get<string>('provider') || 'openai';
  const model = (cfg.get<string>('model') || '').trim();
  const writingStyle = pickEnum(cfg.get<string>('writingStyle'), WRITING_STYLES, 'Default');
  const promptPattern = resolvePromptPattern(cfg.get<string>('promptPattern') || undefined);
  const promptPersona = pickEnum(
    cfg.get<string>('promptPersona'),
    PROMPT_PERSONAS,
    'Auto',
  );
  const customPersona = (cfg.get<string>('customPersona') || '').trim();
  const promptFormat = pickEnum(cfg.get<string>('promptFormat'), PROMPT_FORMATS, 'Auto');
  const promptModel = (cfg.get<string>('promptModel') || '').trim();
  return {
    provider,
    model,
    writingStyle,
    promptPattern,
    promptPersona,
    customPersona,
    promptFormat,
    promptModel,
  };
}

export function readPromptParams(): PromptParams {
  const s = readSettings();
  return {
    pattern: s.promptPattern,
    persona: resolvePromptPersona(s.promptPersona, s.customPersona),
    format: s.promptFormat,
  };
}

export async function updateSettings(
  patch: Partial<{
    provider: string;
    model: string;
    writingStyle: string;
    promptPattern: string;
    promptPersona: string;
    customPersona: string;
    promptFormat: string;
    promptModel: string;
  }>,
): Promise<void> {
  const cfg = vscode.workspace.getConfiguration('lexai');
  const target = vscode.ConfigurationTarget.Global;
  const entries = Object.entries(patch) as [keyof typeof patch, string | undefined][];
  for (const [key, value] of entries) {
    if (value === undefined) continue;
    await cfg.update(key, value, target);
  }
}

export async function resolveConfig(
  context: vscode.ExtensionContext,
): Promise<{ config?: LexAIConfig; error?: string }> {
  const settings = readSettings();
  const apiKey = (await context.secrets.get(SECRET_API_KEY))?.trim();
  if (!apiKey) {
    return {
      error:
        'No API key configured. Run “LexAI: Open Settings” or “LexAI: Set API Key”, then try again.',
    };
  }

  const keyProvider = context.globalState.get<string>(GLOBAL_KEY_PROVIDER);
  if (keyProvider && keyProvider !== settings.provider) {
    return {
      error:
        `Your saved API key was entered for ${providerLabel(keyProvider)}, but the selected provider is ${providerLabel(settings.provider)}. ` +
        `Open LexAI Settings and enter a ${providerLabel(settings.provider)} key (or change the provider).`,
    };
  }

  const spec = PROVIDER_SPECS[settings.provider];
  if (!spec) {
    return { error: `Unknown provider: "${settings.provider}". Open LexAI Settings.` };
  }

  return {
    config: {
      provider: settings.provider,
      apiKey,
      model: settings.model || spec.defaultModel,
      keyProvider: keyProvider || settings.provider,
    },
  };
}

export async function storeApiKey(
  context: vscode.ExtensionContext,
  apiKey: string,
  provider: string,
): Promise<void> {
  await context.secrets.store(SECRET_API_KEY, apiKey.trim());
  await context.globalState.update(GLOBAL_KEY_PROVIDER, provider);
}

export async function clearApiKey(context: vscode.ExtensionContext): Promise<void> {
  await context.secrets.delete(SECRET_API_KEY);
  await context.globalState.update(GLOBAL_KEY_PROVIDER, undefined);
}

export async function hasApiKey(context: vscode.ExtensionContext): Promise<boolean> {
  const key = await context.secrets.get(SECRET_API_KEY);
  return Boolean(key && key.trim());
}

export function settingsCatalog() {
  return {
    providers: Object.keys(PROVIDER_SPECS).map((id) => ({
      id,
      label: providerLabel(id),
      defaultModel: PROVIDER_SPECS[id].defaultModel,
    })),
    writingStyles: [...WRITING_STYLES],
    promptPatterns: PROMPT_PATTERNS.map((p) => ({
      id: p.id,
      label: p.label,
      group: p.group,
      hint: p.hint,
    })),
    promptPersonas: [...PROMPT_PERSONAS],
    promptFormats: [...PROMPT_FORMATS],
  };
}
