import { DEEPSEEK_DIR, SETTINGS_FILE, readJsonFile } from '@cockpit/shared-utils';
import { getSessionTitle } from '../state/globalState';
import { runSdkLoop, type BuildSdkOptions } from './shared/sdkLoop';
import type { DispatchParams, EngineSpec, RunCtx } from './types';

// DeepSeek's Anthropic-compatible endpoint. https://api-docs.deepseek.com/zh-cn/guides/anthropic_api
const DEEPSEEK_BASE_URL = 'https://api.deepseek.com/anthropic';
const DEFAULT_MODEL = 'deepseek-v4-pro';
// Used by the SDK for fast/small subtasks (title gen, compaction).
const SMALL_FAST_MODEL = 'deepseek-v4-flash';
const ALLOWED_MODELS = new Set(['deepseek-v4-flash', 'deepseek-v4-pro']);

interface CockpitSettings {
  engines?: { deepseek?: { apiKey?: string; model?: string } };
  [key: string]: unknown;
}

async function readSettings(): Promise<CockpitSettings> {
  return readJsonFile<CockpitSettings>(SETTINGS_FILE, {});
}

function resolveModel(requested: string | undefined, saved: string | undefined): string {
  if (typeof requested === 'string' && ALLOWED_MODELS.has(requested)) return requested;
  if (saved && ALLOWED_MODELS.has(saved)) return saved;
  return DEFAULT_MODEL;
}

/** Inject DeepSeek's Anthropic-compatible env. We must REMOVE ANTHROPIC_AUTH_TOKEN (not blank it):
 *  some SDK paths check "is defined" and would emit an empty Bearer header → 401. */
function buildDeepseekEnv(apiKey: string, model: string): Record<string, string | undefined> {
  const { ANTHROPIC_AUTH_TOKEN: _t, ANTHROPIC_API_KEY: _k, ...inherited } = process.env;
  void _t; void _k;
  return {
    ...inherited,
    ANTHROPIC_BASE_URL: DEEPSEEK_BASE_URL,
    ANTHROPIC_API_KEY: apiKey, // DeepSeek sends this as x-api-key (fully supported)
    ANTHROPIC_MODEL: model,
    ANTHROPIC_SMALL_FAST_MODEL: SMALL_FAST_MODEL,
    CLAUDE_CONFIG_DIR: DEEPSEEK_DIR,
    DISABLE_PROMPT_CACHING: '1', // DeepSeek runs its own server-side prefix KV cache
    CLAUDE_CODE_USE_BEDROCK: '0',
    CLAUDE_CODE_USE_VERTEX: '0',
    CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: '1',
  };
}

function buildDeepseekOptions(ctx: RunCtx, env: Record<string, string | undefined>): BuildSdkOptions {
  return (abort, resume) => ({
    ...(resume && { resume }),
    ...(ctx.cwd && { cwd: ctx.cwd }),
    settingSources: ['user', 'project', 'local'] as Array<'user' | 'project' | 'local'>,
    permissionMode: 'bypassPermissions' as const,
    allowDangerouslySkipPermissions: true,
    includePartialMessages: true,
    abortController: abort,
    env,
  });
}

export const deepseekSpec: EngineSpec = {
  name: 'deepseek',
  // Pre-check BEFORE startRun: API key must exist; resolve model into params (no registry pollution).
  async preflight(params: DispatchParams) {
    const settings = await readSettings();
    const apiKey = settings.engines?.deepseek?.apiKey?.trim();
    if (!apiKey) {
      return {
        ok: false as const,
        status: 400,
        error: 'DeepSeek API key is not configured. Open the DeepSeek picker in the chat header to set one.',
      };
    }
    params.model = resolveModel(typeof params.model === 'string' ? params.model : undefined, settings.engines?.deepseek?.model);
    return { ok: true as const };
  },
  runner: {
    async run(ctx) {
      const settings = await readSettings();
      const apiKey = settings.engines?.deepseek?.apiKey?.trim() ?? ''; // preflight guaranteed non-empty
      const model = typeof ctx.params.model === 'string' ? ctx.params.model : DEFAULT_MODEL;
      const env = buildDeepseekEnv(apiKey, model);
      await runSdkLoop(ctx, buildDeepseekOptions(ctx, env));
    },
    resolveTitle: (cwd, sessionId) => getSessionTitle(cwd, sessionId),
  },
};
