/**
 * Tests for API Error Handler Utility
 * FE-TEST-004: Test API error handler utility functions
 */

import { describe, it, expect, vi, beforeEach } from 'vitest';
import { AxiosError } from 'axios';
import {
  parseApiError,
  formatErrorMessage,
  getValidationErrors,
} from './apiErrorHandler';
import type { ApiError } from '@/schemas/apiSchemas';

// Mock timeoutHandler
vi.mock('./timeoutHandler', () => ({
  isTimeoutError: vi.fn((error: unknown) => {
    if (error && typeof error === 'object' && 'code' in error) {
      return (
        (error as any).code === 'ECONNABORTED' ||
        (error as any).code === 'ETIMEDOUT'
      );
    }
    return false;
  }),
  TIMEOUT_MESSAGES: {
    timeout: 'Request timeout',
  },
}));

describe('apiErrorHandler utilities', () => {
  describe('parseApiError', () => {
    it('should return ApiError as-is', () => {
      const error: ApiError = {
        code: 404,
        message: 'Not found',
        timestamp: new Date().toISOString(),
      };
      const result = parseApiError(error);
      expect(result).toEqual(error);
    });

    it('should parse AxiosError with standard format', () => {
      const axiosError = {
        isAxiosError: true,
        response: {
          status: 404,
          data: {
            success: false,
            error: {
              code: 404,
              message: 'Not found',
              timestamp: new Date().toISOString(),
            },
          },
        },
      } as unknown as AxiosError;

      const result = parseApiError(axiosError);
      expect(result.code).toBe(404);
      expect(result.message).toBe('Not found');
    });

    it('should parse AxiosError with Gin middleware format', () => {
      const axiosError = {
        isAxiosError: true,
        response: {
          status: 422,
          data: {
            error: {
              code: 422,
              message: 'Validation failed',
            },
          },
        },
      } as unknown as AxiosError;

      const result = parseApiError(axiosError);
      expect(result.code).toBe(422);
      expect(result.message).toBe('Validation failed');
    });

    it('should parse network error', () => {
      const axiosError = {
        isAxiosError: true,
        request: {},
        response: undefined,
      } as unknown as AxiosError;

      const result = parseApiError(axiosError);
      expect(result.code).toBe(0);
      expect(result.message).toContain('Network error');
    });

    it('should parse timeout error', () => {
      const axiosError = {
        isAxiosError: true,
        request: {},
        response: undefined,
        code: 'ECONNABORTED',
      } as unknown as AxiosError;

      const result = parseApiError(axiosError);
      expect(result.code).toBe(0);
      expect(result.message).toBe('Request timeout');
    });

    it('should parse rate limit error with headers', () => {
      const axiosError = {
        isAxiosError: true,
        response: {
          status: 429,
          headers: {
            'x-ratelimit-limit': '100',
            'x-ratelimit-remaining': '0',
            'x-ratelimit-reset': String(Math.floor(Date.now() / 1000) + 60),
            'retry-after': '60',
          },
          data: {
            error: {
              message: 'Rate limit exceeded',
            },
          },
        },
      } as unknown as AxiosError;

      const result = parseApiError(axiosError);
      expect(result.code).toBe(429);
      expect(result.rate_limit).toBeDefined();
      expect(result.retry_after).toBeDefined();
    });

    it('should parse service unavailable error', () => {
      const axiosError = {
        isAxiosError: true,
        response: {
          status: 503,
          data: {
            message: 'Service unavailable',
          },
        },
      } as unknown as AxiosError;

      const result = parseApiError(axiosError);
      expect(result.code).toBe(503);
      expect(result.message).toContain('indisponible');
    });

    it('should parse standard Error', () => {
      const error = new Error('Test error');
      const result = parseApiError(error);
      expect(result.code).toBe(0);
      expect(result.message).toBe('Test error');
    });

    it('should handle unknown error', () => {
      const result = parseApiError(null);
      expect(result.code).toBe(0);
      expect(result.message).toBe('An unexpected error occurred');
    });
  });

  describe('formatErrorMessage', () => {
    it('should format simple error', () => {
      const error: ApiError = {
        code: 404,
        message: 'Not found',
        timestamp: new Date().toISOString(),
      };
      const result = formatErrorMessage(error);
      expect(result).toBe('Not found');
    });

    it('should include validation details', () => {
      const error: ApiError = {
        code: 422,
        message: 'Validation failed',
        timestamp: new Date().toISOString(),
        details: [
          { field: 'email', message: 'Invalid email' },
          { field: 'password', message: 'Too short' },
        ],
      };
      const result = formatErrorMessage(error);
      expect(result).toContain('email');
      expect(result).toContain('password');
    });

    it('should include request_id in dev mode', () => {
      const error: ApiError = {
        code: 500,
        message: 'Server error',
        timestamp: new Date().toISOString(),
        request_id: 'req-123',
      };
      const result = formatErrorMessage(error, true);
      expect(result).toContain('req-123');
    });
  });

  describe('getValidationErrors', () => {
    it('should extract validation errors', () => {
      const error: ApiError = {
        code: 422,
        message: 'Validation failed',
        timestamp: new Date().toISOString(),
        details: [
          { field: 'email', message: 'Invalid email' },
          { field: 'password', message: 'Too short' },
        ],
      };
      const result = getValidationErrors(error);
      expect(result.email).toBe('Invalid email');
      expect(result.password).toBe('Too short');
    });

    it('should return empty object for errors without details', () => {
      const error: ApiError = {
        code: 404,
        message: 'Not found',
        timestamp: new Date().toISOString(),
      };
      const result = getValidationErrors(error);
      expect(result).toEqual({});
    });

    it('should filter out invalid details', () => {
      const error: ApiError = {
        code: 422,
        message: 'Validation failed',
        timestamp: new Date().toISOString(),
        details: [
          { field: 'email', message: 'Invalid email' },
          { field: '', message: 'No field' },
          { message: 'No field' },
        ] as any,
      };
      const result = getValidationErrors(error);
      expect(result.email).toBe('Invalid email');
      expect(result['']).toBeUndefined();
    });
  });
});
