'use strict';

const SETUP_PROVIDER_TYPES = Object.freeze([
  'anthropic',
  'openai',
  'google',
  'ollama',
  'deepseek',
  'moonshot',
]);

const SETUP_PROVIDER_NAMES = Object.freeze({
  anthropic: 'Anthropic',
  openai: 'OpenAI',
  google: 'Google Gemini',
  ollama: 'Ollama (Local)',
  deepseek: 'DeepSeek',
  moonshot: 'Moonshot / Kimi',
});

const SETUP_PROVIDER_ENV_KEYS = Object.freeze({
  anthropic: 'ANTHROPIC_API_KEY',
  openai: 'OPENAI_API_KEY',
  google: 'GOOGLE_API_KEY',
  deepseek: 'DEEPSEEK_API_KEY',
  moonshot: 'MOONSHOT_API_KEY',
});

const SETUP_LOCAL_PROVIDER_TYPES = Object.freeze([
  'ollama',
  'mlx',
]);

const SETUP_KEYLESS_AUTH_METHODS = Object.freeze({
  anthropic: ['claude_cli', 'oauth_proxy', 'devbox'],
  openai: ['codex_cli'],
});

function sanitizeSetupProviderType(value) {
  const sanitized = typeof value === 'string'
    ? value.toLowerCase().replace(/[^a-z]/g, '').slice(0, 20)
    : '';
  if (['kimi', 'kimik', 'kimik2', 'moonshotai', 'moonshotkimi'].includes(sanitized)) return 'moonshot';
  return sanitized;
}

function sanitizeSetupModel(value) {
  return typeof value === 'string'
    ? value.replace(/[\r\n\s]/g, '').slice(0, 100)
    : '';
}

function isSetupProviderType(value) {
  return SETUP_PROVIDER_TYPES.includes(sanitizeSetupProviderType(value));
}

function setupProviderTypeList() {
  return SETUP_PROVIDER_TYPES.join(', ');
}

function resolveSetupDefaultSelection({ type, model, storedModel }) {
  const providerType = sanitizeSetupProviderType(type);
  if (!isSetupProviderType(providerType)) {
    return {
      ok: false,
      type: providerType,
      error: 'Invalid provider type. Must be one of: ' + setupProviderTypeList(),
    };
  }
  const requestedModel = sanitizeSetupModel(model);
  const fallbackModel = sanitizeSetupModel(storedModel);
  return {
    ok: true,
    type: providerType,
    requestedModel,
    targetModel: requestedModel || fallbackModel,
  };
}

function setupProviderAuthMethodHasRuntimeAccess(type, authMethod) {
  const providerType = sanitizeSetupProviderType(type);
  const method = typeof authMethod === 'string' ? authMethod.trim() : '';
  return (SETUP_KEYLESS_AUTH_METHODS[providerType] || []).includes(method);
}

function setupProviderHasRuntimeAccess({ type, env = process.env, authMethod = '', hasStoredKey = false } = {}) {
  const providerType = sanitizeSetupProviderType(type);
  if (SETUP_LOCAL_PROVIDER_TYPES.includes(providerType)) return true;
  if (hasStoredKey) return true;
  if (setupProviderAuthMethodHasRuntimeAccess(providerType, authMethod)) return true;

  if (providerType === 'anthropic') {
    return !!(env.ANTHROPIC_API_KEY || env.ANTHROPIC_AUTH_TOKEN || env.ANTHROPIC_BASE_URL);
  }
  if (providerType === 'openai') {
    return !!env.OPENAI_API_KEY;
  }
  if (providerType === 'google') {
    return !!(env.GOOGLE_API_KEY || env.GEMINI_API_KEY);
  }
  if (providerType === 'deepseek') {
    return !!env.DEEPSEEK_API_KEY;
  }
  if (providerType === 'moonshot') {
    return !!env.MOONSHOT_API_KEY;
  }
  return false;
}

function isAutoDetectedSetupProvider(provider = {}) {
  const id = String(provider.id || '').toLowerCase();
  const name = String(provider.name || '').toLowerCase();
  return /\bauto[-_ ]?detected\b/.test(name)
    || /(?:^|[-_])auto(?:$|[-_])/.test(id)
    || /(?:^|[-_])env(?:$|[-_])/.test(id);
}

function setupProviderInstanceScore(provider = {}, defaultProvider = '') {
  const type = sanitizeSetupProviderType(provider.type);
  const canonicalName = SETUP_PROVIDER_NAMES[type] || type;
  const name = String(provider.name || '').trim();
  const id = String(provider.id || '').trim();
  let score = 0;
  if (provider.enabled) score += 1000000;
  if (provider.has_stored_key) score += 150000;
  else if (provider.has_key || SETUP_LOCAL_PROVIDER_TYPES.includes(type)) score += 100000;
  if (provider.model) score += 30000;
  if (name === canonicalName) score += 20000;
  if (!isAutoDetectedSetupProvider(provider)) score += 10000;
  if (type && id === `${type}-default`) score += 5000;
  if (type && type === sanitizeSetupProviderType(defaultProvider)) score += 2500;
  if (provider.auth_method && provider.auth_method !== 'api_key') score += 1000;
  return score;
}

function collapseSetupProviderInstances(providers, { defaultProvider = '' } = {}) {
  const groups = new Map();
  const invalidProviders = [];
  const source = Array.isArray(providers) ? providers : [];

  source.forEach((provider, index) => {
    const type = sanitizeSetupProviderType(provider && provider.type);
    if (!isSetupProviderType(type)) {
      invalidProviders.push(provider);
      return;
    }
    if (!groups.has(type)) groups.set(type, { firstIndex: index, providers: [] });
    groups.get(type).providers.push({ ...(provider || {}), type });
  });

  const collapsed = [];
  const duplicateDiagnostics = [];

  for (const [type, group] of groups.entries()) {
    const ranked = group.providers.slice().sort((a, b) => {
      const byScore = setupProviderInstanceScore(b, defaultProvider) - setupProviderInstanceScore(a, defaultProvider);
      if (byScore) return byScore;
      const byUpdated = (Date.parse(b.updated_at || b.created_at || '') || 0)
        - (Date.parse(a.updated_at || a.created_at || '') || 0);
      if (byUpdated) return byUpdated;
      return String(a.id || '').localeCompare(String(b.id || ''));
    });
    const selected = ranked[0];
    const ids = group.providers.map((provider) => String(provider.id || '')).filter(Boolean);
    const provider = {
      ...selected,
      name: SETUP_PROVIDER_NAMES[type] || selected.name || type,
      instance_count: group.providers.length,
      instance_ids: ids,
      duplicate_provider_ids: ids.filter((id) => id !== selected.id),
      selected_provider_id: selected.id || null,
      _firstIndex: group.firstIndex,
    };
    collapsed.push(provider);
    if (group.providers.length > 1) {
      duplicateDiagnostics.push({
        type,
        selected_provider_id: selected.id || null,
        provider_ids: ids,
      });
    }
  }

  collapsed.sort((a, b) => a._firstIndex - b._firstIndex);
  for (const provider of collapsed) delete provider._firstIndex;
  return {
    providers: collapsed,
    duplicateDiagnostics,
    invalidProviderCount: invalidProviders.length,
  };
}

module.exports = {
  SETUP_PROVIDER_TYPES,
  SETUP_PROVIDER_NAMES,
  SETUP_PROVIDER_ENV_KEYS,
  SETUP_LOCAL_PROVIDER_TYPES,
  SETUP_KEYLESS_AUTH_METHODS,
  sanitizeSetupProviderType,
  sanitizeSetupModel,
  isSetupProviderType,
  setupProviderTypeList,
  resolveSetupDefaultSelection,
  setupProviderAuthMethodHasRuntimeAccess,
  setupProviderHasRuntimeAccess,
  isAutoDetectedSetupProvider,
  setupProviderInstanceScore,
  collapseSetupProviderInstances,
};
