import { describe, it, expect } from 'vitest';
import {
  shouldAutoSwapBaseUrl,
  formatDateTime,
  sourceLabel,
  sourceColor,
  PROVIDER_DEFAULTS,
  extractErrorMessage,
} from './helpers';

describe('AiConfig helpers', () => {
  describe('shouldAutoSwapBaseUrl', () => {
    it('swaps to default on first provider selection', () => {
      const result = shouldAutoSwapBaseUrl('DEEPSEEK', '', null);
      expect(result.shouldSwap).toBe(true);
      expect(result.baseUrl).toBe(PROVIDER_DEFAULTS.DEEPSEEK);
    });

    it('swaps when current baseUrl matches previous provider default', () => {
      const result = shouldAutoSwapBaseUrl('DEEPSEEK', 'https://api.openai.com/v1', 'OPENAI');
      expect(result.shouldSwap).toBe(true);
      expect(result.baseUrl).toBe(PROVIDER_DEFAULTS.DEEPSEEK);
    });

    it('swaps when current baseUrl is empty', () => {
      const result = shouldAutoSwapBaseUrl('DEEPSEEK', '', 'OPENAI');
      expect(result.shouldSwap).toBe(true);
    });

    it('keeps custom baseUrl unchanged', () => {
      const result = shouldAutoSwapBaseUrl('OPENAI', 'https://custom.api.com/v1', 'DEEPSEEK');
      expect(result.shouldSwap).toBe(false);
      expect(result.baseUrl).toBe('https://custom.api.com/v1');
    });
  });

  describe('formatDateTime', () => {
    it('returns hyphen for null', () => {
      expect(formatDateTime(null)).toBe('-');
    });

    it('returns Chinese locale string for ISO date', () => {
      expect(formatDateTime('2024-01-15T10:30:00Z')).toContain('2024');
    });
  });

  describe('sourceLabel', () => {
    it('returns Chinese labels', () => {
      expect(sourceLabel('database')).toBe('数据库');
      expect(sourceLabel('environment')).toBe('环境变量');
      expect(sourceLabel('none')).toBe('未配置');
    });
  });

  describe('sourceColor', () => {
    it('returns correct colors', () => {
      expect(sourceColor('database')).toBe('green');
      expect(sourceColor('environment')).toBe('blue');
      expect(sourceColor('none')).toBe('default');
    });
  });

  describe('extractErrorMessage', () => {
    it('extracts message from server error response (interceptor unwraps to { message })', () => {
      // The Axios interceptor at api/index.ts does Promise.reject(err.response?.data || err).
      // For server errors, the rejection value is err.response.data — typically { message: '...' }.
      const err = { message: 'API出错' };
      expect(extractErrorMessage(err)).toBe('API出错');
    });

    it('falls back to message property', () => {
      const err = { message: 'Network error' };
      expect(extractErrorMessage(err)).toBe('Network error');
    });

    it('falls back to default on unknown type', () => {
      expect(extractErrorMessage('unknown string')).toBe('操作失败');
      expect(extractErrorMessage(null)).toBe('操作失败');
      expect(extractErrorMessage(undefined)).toBe('操作失败');
    });

    it('sanitizes: newlines replaced with spaces', () => {
      const err = { message: 'line1\nline2\r\nline3' };
      expect(extractErrorMessage(err)).toBe('line1 line2 line3');
    });

    it('sanitizes: message > 120 chars truncated with ellipsis', () => {
      const long = 'x'.repeat(200);
      const err = { message: long };
      const result = extractErrorMessage(err);
      expect(result).toHaveLength(121); // 120 + '…' (1 char)
      expect(result.endsWith('\u2026')).toBe(true);
    });

    it('sanitizes: empty trimmed message falls back', () => {
      const err = { message: '   ' };
      expect(extractErrorMessage(err)).toBe('操作失败');
    });

    it('sanitizes: plain object message property sanitized', () => {
      const err = {
        message: '  some \n\nerror  \r\nmessage  ',
      };
      expect(extractErrorMessage(err)).toBe('some error message');
    });
  });
});
