import { ClientSideValidator } from '../ClientSideValidator';

describe('ClientSideValidator', () => {
  let validator: ClientSideValidator;

  beforeEach(() => {
    validator = new ClientSideValidator();
  });

  describe('detectFileType', () => {
    it('should detect PNG file type from magic bytes', async () => {
      // PNG magic bytes: 89 50 4E 47 0D 0A 1A 0A
      const pngBuffer = new ArrayBuffer(12);
      const view = new Uint8Array(pngBuffer);
      view.set([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d]);

      const result = await validator.detectFileType(pngBuffer);
      expect(result).toBe('image/png');
    });

    it('should detect JPEG file type from magic bytes', async () => {
      // JPEG magic bytes: FF D8 FF
      const jpegBuffer = new ArrayBuffer(6);
      const view = new Uint8Array(jpegBuffer);
      view.set([0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10]);

      const result = await validator.detectFileType(jpegBuffer);
      expect(result).toBe('image/jpeg');
    });

    it('should detect PDF file type from magic bytes', async () => {
      // PDF magic bytes: 25 50 44 46 (% P D F)
      const pdfBuffer = new ArrayBuffer(6);
      const view = new Uint8Array(pdfBuffer);
      view.set([0x25, 0x50, 0x44, 0x46, 0x2d, 0x31]);

      const result = await validator.detectFileType(pdfBuffer);
      expect(result).toBe('application/pdf');
    });

    it('should detect GIF file type from magic bytes', async () => {
      // GIF magic bytes: 47 49 46 (GIF)
      const gifBuffer = new ArrayBuffer(6);
      const view = new Uint8Array(gifBuffer);
      view.set([0x47, 0x49, 0x46, 0x38, 0x39, 0x61]);

      const result = await validator.detectFileType(gifBuffer);
      expect(result).toBe('image/gif');
    });

    it('should return null for empty buffer', async () => {
      const emptyBuffer = new ArrayBuffer(0);
      const result = await validator.detectFileType(emptyBuffer);
      expect(result).toBeNull();
    });

    it('should return null for unrecognized file type', async () => {
      const unknownBuffer = new ArrayBuffer(4);
      const view = new Uint8Array(unknownBuffer);
      view.set([0x00, 0x01, 0x02, 0x03]);

      const result = await validator.detectFileType(unknownBuffer);
      expect(result).toBeNull();
    });
  });

  describe('validateFile', () => {
    it('should validate matching MIME types', async () => {
      const pngBuffer = new ArrayBuffer(12);
      const view = new Uint8Array(pngBuffer);
      view.set([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d]);

      const file = new File([pngBuffer], 'test.png', { type: 'image/png' });
      const result = await validator.validateFile(file, 'image/png');

      expect(result.isValid).toBe(true);
      expect(result.detectedMime).toBe('image/png');
      expect(result.error).toBeUndefined();
    });

    it('should reject mismatched MIME types', async () => {
      const pngBuffer = new ArrayBuffer(12);
      const view = new Uint8Array(pngBuffer);
      view.set([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d]);

      const file = new File([pngBuffer], 'test.png', { type: 'image/jpeg' });
      const result = await validator.validateFile(file, 'image/jpeg');

      expect(result.isValid).toBe(false);
      expect(result.detectedMime).toBe('image/png');
      expect(result.error).toContain('File type mismatch');
    });

    it('should handle unrecognized file types', async () => {
      const unknownBuffer = new ArrayBuffer(4);
      const view = new Uint8Array(unknownBuffer);
      view.set([0x00, 0x01, 0x02, 0x03]);

      const file = new File([unknownBuffer], 'test.bin', { type: 'application/octet-stream' });
      const result = await validator.validateFile(file, 'application/octet-stream');

      expect(result.isValid).toBe(false);
      expect(result.detectedMime).toBeNull();
      expect(result.error).toContain('Unable to detect file type');
    });

    it('should handle missing file', async () => {
      const result = await validator.validateFile(null as any, 'image/png');

      expect(result.isValid).toBe(false);
      expect(result.error).toContain('No file provided');
    });
  });

  describe('isAllowedMimeType', () => {
    it('should return true for empty allowed list', () => {
      const result = validator.isAllowedMimeType('image/png', []);
      expect(result).toBe(true);
    });

    it('should return true for allowed MIME type', () => {
      const result = validator.isAllowedMimeType('image/png', [
        'image/png',
        'image/jpeg',
      ]);
      expect(result).toBe(true);
    });

    it('should return false for disallowed MIME type', () => {
      const result = validator.isAllowedMimeType('application/exe', [
        'image/png',
        'image/jpeg',
      ]);
      expect(result).toBe(false);
    });
  });

  describe('validateUpload', () => {
    it('should validate matching MIME type and allowed list', async () => {
      const pngBuffer = new ArrayBuffer(12);
      const view = new Uint8Array(pngBuffer);
      view.set([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d]);

      const file = new File([pngBuffer], 'test.png', { type: 'image/png' });
      const result = await validator.validateUpload(file, 'image/png', [
        'image/png',
        'image/jpeg',
      ]);

      expect(result.isValid).toBe(true);
    });

    it('should reject MIME type mismatch', async () => {
      const pngBuffer = new ArrayBuffer(12);
      const view = new Uint8Array(pngBuffer);
      view.set([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d]);

      const file = new File([pngBuffer], 'test.png', { type: 'image/jpeg' });
      const result = await validator.validateUpload(file, 'image/jpeg', [
        'image/png',
        'image/jpeg',
      ]);

      expect(result.isValid).toBe(false);
      expect(result.error).toContain('File type mismatch');
    });

    it('should reject MIME type not in allowed list', async () => {
      const pngBuffer = new ArrayBuffer(12);
      const view = new Uint8Array(pngBuffer);
      view.set([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d]);

      const file = new File([pngBuffer], 'test.png', { type: 'image/png' });
      const result = await validator.validateUpload(file, 'image/png', [
        'image/jpeg',
        'application/pdf',
      ]);

      expect(result.isValid).toBe(false);
      expect(result.error).toContain('not allowed');
    });
  });
});
