// src/services/processingErrors.test.ts
import { describe, it, expect } from 'vitest';
import {
  FlyerProcessingError,
  PdfConversionError,
  AiDataValidationError,
  GeocodingFailedError,
  UnsupportedFileTypeError,
  TransformationError,
  DatabaseError,
  ImageConversionError,
} from './processingErrors';

describe('Processing Errors', () => {
  describe('FlyerProcessingError', () => {
    it('should create an error with the correct message, name, and inheritance', () => {
      const message = 'A generic processing error occurred.';
      const error = new FlyerProcessingError(message);

      expect(error).toBeInstanceOf(Error);
      expect(error).toBeInstanceOf(FlyerProcessingError);
      expect(error.message).toBe(message);
      expect(error.name).toBe('FlyerProcessingError');
      expect(error.errorCode).toBe('UNKNOWN_ERROR');
      expect(error.userMessage).toBe(message);
    });

    it('should allow setting a custom errorCode and userMessage', () => {
      const message = 'Internal error';
      const errorCode = 'CUSTOM_ERROR';
      const userMessage = 'Something went wrong for you.';
      const error = new FlyerProcessingError(message, errorCode, userMessage);

      expect(error.errorCode).toBe(errorCode);
      expect(error.userMessage).toBe(userMessage);
    });

    it('should return the correct error payload', () => {
      const message = 'Internal error';
      const errorCode = 'CUSTOM_ERROR';
      const userMessage = 'Something went wrong for you.';
      const error = new FlyerProcessingError(message, errorCode, userMessage);

      expect(error.toErrorPayload()).toEqual({
        errorCode,
        message: userMessage,
      });
    });
  });

  describe('PdfConversionError', () => {
    it('should create an error that inherits from FlyerProcessingError', () => {
      const message = 'PDF conversion failed.';
      const error = new PdfConversionError(message);

      expect(error).toBeInstanceOf(Error);
      expect(error).toBeInstanceOf(FlyerProcessingError);
      expect(error).toBeInstanceOf(PdfConversionError);
      expect(error.message).toBe(message);
      expect(error.name).toBe('PdfConversionError');
      expect(error.stderr).toBeUndefined();
      expect(error.errorCode).toBe('PDF_CONVERSION_FAILED');
    });

    it('should store the stderr property if provided', () => {
      const message = 'pdftocairo failed.';
      const stderr = 'pdftocairo: command not found';
      const error = new PdfConversionError(message, stderr);

      expect(error.message).toBe(message);
      expect(error.stderr).toBe(stderr);
    });

    it('should include stderr in the error payload', () => {
      const message = 'pdftocairo failed.';
      const stderr = 'pdftocairo: command not found';
      const error = new PdfConversionError(message, stderr);

      const payload = error.toErrorPayload();
      expect(payload.errorCode).toBe('PDF_CONVERSION_FAILED');
      expect(payload.stderr).toBe(stderr);
    });
  });

  describe('AiDataValidationError', () => {
    it('should create an error with validation details and raw data', () => {
      const message = 'AI response validation failed.';
      const validationErrors = { fieldErrors: { store_name: ['Store name cannot be empty'] } };
      const rawData = { store_name: '', items: [] };
      const error = new AiDataValidationError(message, validationErrors, rawData);

      expect(error).toBeInstanceOf(Error);
      expect(error).toBeInstanceOf(FlyerProcessingError);
      expect(error).toBeInstanceOf(AiDataValidationError);
      expect(error.message).toBe(message);
      expect(error.name).toBe('AiDataValidationError');
      expect(error.validationErrors).toEqual(validationErrors);
      expect(error.rawData).toEqual(rawData);
      expect(error.errorCode).toBe('AI_VALIDATION_FAILED');
    });

    it('should include validationErrors and rawData in the error payload', () => {
      const message = 'AI response validation failed.';
      const validationErrors = { fieldErrors: { store_name: ['Store name cannot be empty'] } };
      const rawData = { store_name: '', items: [] };
      const error = new AiDataValidationError(message, validationErrors, rawData);

      const payload = error.toErrorPayload();
      expect(payload.errorCode).toBe('AI_VALIDATION_FAILED');
      expect(payload.validationErrors).toEqual(validationErrors);
      expect(payload.rawData).toEqual(rawData);
    });
  });

  describe('TransformationError', () => {
    it('should create an error with the correct message and code', () => {
      const message = 'Transformation failed.';
      const error = new TransformationError(message);

      expect(error).toBeInstanceOf(FlyerProcessingError);
      expect(error).toBeInstanceOf(TransformationError);
      expect(error.message).toBe(message);
      expect(error.errorCode).toBe('TRANSFORMATION_FAILED');
      expect(error.userMessage).toBe('There was a problem transforming the flyer data. Please check the input.');
    });
  });

  describe('DatabaseError', () => {
    it('should create an error with the correct message and code', () => {
      const message = 'DB failed.';
      const error = new DatabaseError(message);

      expect(error).toBeInstanceOf(FlyerProcessingError);
      expect(error).toBeInstanceOf(DatabaseError);
      expect(error.message).toBe(message);
      expect(error.errorCode).toBe('DATABASE_ERROR');
      expect(error.userMessage).toBe('A database operation failed. Please try again later.');
    });
  });

  describe('ImageConversionError', () => {
    it('should create an error with the correct message and code', () => {
      const message = 'Image conversion failed.';
      const error = new ImageConversionError(message);

      expect(error).toBeInstanceOf(FlyerProcessingError);
      expect(error).toBeInstanceOf(ImageConversionError);
      expect(error.message).toBe(message);
      expect(error.errorCode).toBe('IMAGE_CONVERSION_FAILED');
      expect(error.userMessage).toBe('The uploaded image could not be processed. It might be corrupt or in an unsupported format.');
    });
  });

  describe('GeocodingFailedError', () => {
    it('should create an error with the correct message, name, and inheritance', () => {
      const message = 'All geocoding providers failed.';
      const error = new GeocodingFailedError(message);

      expect(error).toBeInstanceOf(Error);
      expect(error).toBeInstanceOf(FlyerProcessingError);
      expect(error).toBeInstanceOf(GeocodingFailedError);
      expect(error.message).toBe(message);
      expect(error.name).toBe('GeocodingFailedError');
      expect(error.errorCode).toBe('GEOCODING_FAILED');
    });
  });

  describe('UnsupportedFileTypeError', () => {
    it('should create an error with the correct message, name, and inheritance', () => {
      const message = 'Unsupported file type: .txt';
      const error = new UnsupportedFileTypeError(message);

      expect(error).toBeInstanceOf(Error);
      expect(error).toBeInstanceOf(FlyerProcessingError);
      expect(error).toBeInstanceOf(UnsupportedFileTypeError);
      expect(error.message).toBe(message);
      expect(error.name).toBe('UnsupportedFileTypeError');
      expect(error.errorCode).toBe('UNSUPPORTED_FILE_TYPE');
    });
  });
});
