/**
 * Error Handling Integration Tests
 *
 * Tests the unified error handling system including:
 * - ApiError class
 * - Error handler service
 * - Retry logic
 */

import { describe, it, expect, vi, beforeEach } from 'vitest';
import { AppError, ApiError, ErrorCode, parseApiError, getUserFriendlyMessage } from '@/lib/errors';

describe('Error Handling', () => {
  describe('AppError / ApiError', () => {
    it('should create AppError with correct properties', () => {
      const error = new AppError(
        ErrorCode.INVALID_PARAMETER,
        'Test error',
        { field: 'name' },
        'req_123'
      );

      expect(error.code).toBe(ErrorCode.INVALID_PARAMETER);
      expect(error.message).toBe('Test error');
      expect(error.details).toEqual({ field: 'name' });
      expect(error.requestId).toBe('req_123');
      expect(error.timestamp).toBeDefined();
    });

    it('should use default message if not provided', () => {
      const error = new AppError(ErrorCode.INVALID_PARAMETER);
      expect(error.message).toBe(getUserFriendlyMessage(ErrorCode.INVALID_PARAMETER));
    });

    it('should create AppError from API error', () => {
      const apiError = {
        response: {
          status: 400,
          data: {
            code: '1001',
            message: 'Invalid input',
            details: { field: 'email' },
            request_id: 'req_456',
          },
        },
      };

      const error = AppError.fromApiError(apiError);
      expect(error.code).toBe('1001');
      expect(error.details).toEqual({ field: 'email' });
      expect(error.requestId).toBe('req_456');
    });

    it('should check if error is retryable', () => {
      const retryableError = new AppError(ErrorCode.NETWORK_ERROR);
      const nonRetryableError = new AppError(ErrorCode.INVALID_PARAMETER);

      expect(retryableError.isRetryable()).toBe(true);
      expect(nonRetryableError.isRetryable()).toBe(false);
    });

    it('should convert to JSON', () => {
      const error = new AppError(
        ErrorCode.UNKNOWN_ERROR,
        'Server error',
        { trace: 'abc' }
      );

      const json = error.toJSON();
      expect(json.name).toBe('AppError');
      expect(json.code).toBe(ErrorCode.UNKNOWN_ERROR);
      expect(json.message).toBe('Server error');
      expect(json.details).toEqual({ trace: 'abc' });
    });

    it('should have ApiError as alias', () => {
      const error = new ApiError(ErrorCode.NOT_FOUND);
      expect(error).toBeInstanceOf(AppError);
    });
  });

  describe('parseApiError', () => {
    it('should parse axios error with backend format', () => {
      const axiosError = {
        response: {
          status: 404,
          data: {
            code: '2001',
            message: 'Project not found',
            details: { projectId: '123' },
            request_id: 'req_789',
          },
        },
      };

      const parsed = parseApiError(axiosError);
      expect(parsed.code).toBe('2001');
      expect(parsed.message).toBeDefined();
      expect(parsed.details).toEqual({ projectId: '123' });
      expect(parsed.requestId).toBe('req_789');
    });

    it('should parse HTTP status codes', () => {
      const errors = [
        { response: { status: 400 }, expected: ErrorCode.INVALID_PARAMETER },
        { response: { status: 401 }, expected: ErrorCode.UNAUTHORIZED },
        { response: { status: 403 }, expected: ErrorCode.FORBIDDEN },
        { response: { status: 404 }, expected: ErrorCode.NOT_FOUND },
        { response: { status: 429 }, expected: ErrorCode.RATE_LIMIT_EXCEEDED },
        { response: { status: 500 }, expected: ErrorCode.UNKNOWN_ERROR },
        { response: { status: 503 }, expected: ErrorCode.SERVICE_UNAVAILABLE },
      ];

      errors.forEach(({ response, expected }) => {
        const parsed = parseApiError({ response });
        expect(parsed.code).toBe(expected);
      });
    });

    it('should parse network errors', () => {
      const networkError = {
        request: {},
        message: 'Network Error',
      };

      const parsed = parseApiError(networkError);
      expect(parsed.code).toBe(ErrorCode.NETWORK_ERROR);
    });

    it('should parse timeout errors', () => {
      const timeoutError = {
        code: 'ECONNABORTED',
        message: 'timeout of 5000ms exceeded',
      };

      const parsed = parseApiError(timeoutError);
      expect(parsed.code).toBe(ErrorCode.TIMEOUT_ERROR);
    });

    it('should handle unknown errors', () => {
      const unknownError = {
        message: 'Something went wrong',
      };

      const parsed = parseApiError(unknownError);
      expect(parsed.code).toBe(ErrorCode.UNKNOWN_ERROR);
    });
  });

  describe('getUserFriendlyMessage', () => {
    it('should return user-friendly messages for error codes', () => {
      const message = getUserFriendlyMessage(ErrorCode.NETWORK_ERROR);
      expect(message).toBe('网络连接失败，请检查您的网络');
    });

    it('should return fallback message for unknown codes', () => {
      const message = getUserFriendlyMessage('UNKNOWN_CODE' as ErrorCode, 'Fallback');
      expect(message).toBe('Fallback');
    });

    it('should return default unknown error message', () => {
      const message = getUserFriendlyMessage('UNKNOWN_CODE' as ErrorCode);
      expect(message).toBe('发生未知错误，请重试');
    });
  });
});
