// ---------------------------------------------------------------------------
// AiConfig helpers — pure functions, no React / DOM dependencies
// ---------------------------------------------------------------------------

export type AiProvider = 'OPENAI' | 'DEEPSEEK' | 'OPENAI_COMPATIBLE';

export const PROVIDER_OPTIONS: { value: AiProvider; label: string }[] = [
  { value: 'OPENAI', label: 'OpenAI' },
  { value: 'DEEPSEEK', label: 'DeepSeek' },
  { value: 'OPENAI_COMPATIBLE', label: 'OpenAI 兼容' },
];

export const PROVIDER_DEFAULTS: Record<AiProvider, string> = {
  OPENAI: 'https://api.openai.com/v1',
  DEEPSEEK: 'https://api.deepseek.com',
  OPENAI_COMPATIBLE: '',
} as const;

export const FIXED_PROVIDERS: AiProvider[] = ['OPENAI', 'DEEPSEEK'];

export function formatDateTime(iso: string | null): string {
  if (!iso) return '-';
  return new Date(iso).toLocaleString('zh-CN');
}

export function sourceLabel(source: string): string {
  switch (source) {
    case 'database':
      return '数据库';
    case 'environment':
      return '环境变量';
    default:
      return '未配置';
  }
}

export function sourceColor(source: string): 'green' | 'blue' | 'default' {
  switch (source) {
    case 'database':
      return 'green';
    case 'environment':
      return 'blue';
    default:
      return 'default';
  }
}

export function shouldAutoSwapBaseUrl(
  provider: AiProvider,
  currentBaseUrl: string,
  lastProvider: AiProvider | null,
): { baseUrl: string; shouldSwap: boolean } {
  if (!lastProvider) {
    return { baseUrl: PROVIDER_DEFAULTS[provider], shouldSwap: true };
  }
  const prevDefault = PROVIDER_DEFAULTS[lastProvider];
  if (!currentBaseUrl || currentBaseUrl === prevDefault) {
    return { baseUrl: PROVIDER_DEFAULTS[provider], shouldSwap: true };
  }
  return { baseUrl: currentBaseUrl, shouldSwap: false };
}

/** Extract a safe user-facing error message from any caught value.
 *
 * The Axios interceptor at `api/index.ts` unwraps errors before rejection:
 * `Promise.reject(err.response?.data || err)`. So server errors arrive as
 * `{ message: '...' }` (the unwrapped data) and network errors as the raw
 * `Error` object — never as a raw AxiosError with a `.response` property. */
export function extractErrorMessage(err: unknown, fallback: string = '操作失败'): string {
  let msg = '';

  // standard Error or any object with a string message property
  if (err && typeof err === 'object' && 'message' in err && typeof err.message === 'string') {
    msg = err.message;
  }

  // sanitize: trim, collapse whitespace, strip newlines, truncate
  const trimmed = msg.trim();
  if (!trimmed) return fallback;

  const singleLine = trimmed.replace(/[\n\r]+/g, ' ').replace(/ {2,}/g, ' ');
  return singleLine.length > 120 ? singleLine.slice(0, 120) + '\u2026' : singleLine;
}
