/**
 * Model fetcher — retrieves available models from each provider's API.
 *
 * Each function returns a sorted list of model IDs.
 * Network errors return empty arrays (non-fatal).
 */

export interface ModelInfo {
  id: string;
  name: string;
  provider: string;
}

const TIMEOUT = 8000;

// Known Claude models as ultimate fallback
const KNOWN_CLAUDE_MODELS: ModelInfo[] = [
  { id: 'claude-opus-4-6', name: 'Claude Opus 4.6', provider: 'claude' },
  { id: 'claude-sonnet-4-6', name: 'Claude Sonnet 4.6', provider: 'claude' },
  { id: 'claude-opus-4-5-20251101', name: 'Claude Opus 4.5', provider: 'claude' },
  { id: 'claude-sonnet-4-20250514', name: 'Claude Sonnet 4', provider: 'claude' },
  { id: 'claude-haiku-4-5-20251001', name: 'Claude Haiku 4.5', provider: 'claude' },
];

/**
 * Try to get an API key for Claude:
 * 1. ANTHROPIC_API_KEY env var (explicit)
 * 2. Claude CLI OAuth token from ~/.claude/.credentials.json (auto-detected)
 */
function getClaudeApiKey(): string | null {
  if (process.env.ANTHROPIC_API_KEY) return process.env.ANTHROPIC_API_KEY;
  try {
    const fs = require('fs');
    const path = require('path');
    const home = process.env.HOME || '/home';
    const credPath = path.join(home, '.claude', '.credentials.json');
    const data = JSON.parse(fs.readFileSync(credPath, 'utf8'));
    const token = data?.claudeAiOauth?.accessToken;
    if (token && typeof token === 'string' && token.startsWith('sk-ant-')) {
      // Check if token is expired
      const expiresAt = data.claudeAiOauth.expiresAt;
      if (expiresAt && Date.now() > expiresAt) return null;
      return token;
    }
  } catch { /* credentials file not found or unreadable */ }
  return null;
}

export async function fetchClaudeModels(): Promise<ModelInfo[]> {
  const apiKey = getClaudeApiKey();
  if (!apiKey) return KNOWN_CLAUDE_MODELS;
  try {
    const res = await fetch('https://api.anthropic.com/v1/models?limit=100', {
      headers: {
        'x-api-key': apiKey,
        'anthropic-version': '2023-06-01',
      },
      signal: AbortSignal.timeout(TIMEOUT),
    });
    if (!res.ok) return KNOWN_CLAUDE_MODELS;
    const data = await res.json() as { data?: Array<{ id: string; display_name?: string }> };
    const live = (data.data ?? [])
      .map(m => ({ id: m.id, name: m.display_name ?? m.id, provider: 'claude' }))
      .sort((a, b) => b.id.localeCompare(a.id)); // newest first
    return live.length > 0 ? live : KNOWN_CLAUDE_MODELS;
  } catch {
    return KNOWN_CLAUDE_MODELS;
  }
}

export async function fetchCodexModels(): Promise<ModelInfo[]> {
  const apiKey = process.env.OPENAI_API_KEY;
  if (!apiKey) return [];
  try {
    const res = await fetch('https://api.openai.com/v1/models', {
      headers: { 'Authorization': `Bearer ${apiKey}` },
      signal: AbortSignal.timeout(TIMEOUT),
    });
    if (!res.ok) return [];
    const data = await res.json() as { data?: Array<{ id: string }> };
    return (data.data ?? [])
      .map(m => ({ id: m.id, name: m.id, provider: 'codex' }))
      .sort((a, b) => a.id.localeCompare(b.id));
  } catch {
    return [];
  }
}

export async function fetchOllamaModels(): Promise<ModelInfo[]> {
  try {
    const res = await fetch('http://localhost:11434/api/tags', {
      signal: AbortSignal.timeout(TIMEOUT),
    });
    if (!res.ok) return [];
    const data = await res.json() as { models?: Array<{ name: string; model?: string }> };
    return (data.models ?? [])
      .map(m => ({ id: m.name, name: m.name, provider: 'ollama' }))
      .sort((a, b) => a.id.localeCompare(b.id));
  } catch {
    return [];
  }
}

export async function fetchGeminiModels(): Promise<ModelInfo[]> {
  const apiKey = process.env.GEMINI_API_KEY;
  if (!apiKey) return [];
  try {
    const res = await fetch(
      `https://generativelanguage.googleapis.com/v1beta/models?key=${apiKey}`,
      { signal: AbortSignal.timeout(TIMEOUT) },
    );
    if (!res.ok) return [];
    const data = await res.json() as {
      models?: Array<{ name: string; displayName?: string }>;
    };
    return (data.models ?? [])
      .map(m => ({
        id: m.name.replace('models/', ''),
        name: m.displayName ?? m.name,
        provider: 'gemini',
      }))
      .sort((a, b) => a.id.localeCompare(b.id));
  } catch {
    return [];
  }
}

/**
 * Fetch models for a specific provider.
 */
export async function fetchModelsForProvider(
  provider: string,
): Promise<ModelInfo[]> {
  switch (provider) {
    case 'claude': return fetchClaudeModels();
    case 'codex': return fetchCodexModels();
    case 'ollama': return fetchOllamaModels();
    case 'gemini': return fetchGeminiModels();
    default: return [];
  }
}
