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

// Mock file-type module
jest.mock('file-type', () => ({
  fileTypeFromBuffer: jest.fn(async (buffer: Buffer) => {
    // PNG magic bytes: 89 50 4E 47 0D 0A 1A 0A
    if (buffer[0] === 0x89 && buffer[1] === 0x50 && buffer[2] === 0x4e && buffer[3] === 0x47) {
      return { mime: 'image/png', ext: 'png' };
    }
    // JPEG magic bytes: FF D8 FF
    if (buffer[0] === 0xff && buffer[1] === 0xd8 && buffer[2] === 0xff) {
      return { mime: 'image/jpeg', ext: 'jpg' };
    }
    // PDF magic bytes: 25 50 44 46 (% P D F)
    if (buffer[0] === 0x25 && buffer[1] === 0x50 && buffer[2] === 0x44 && buffer[3] === 0x46) {
      return { mime: 'application/pdf', ext: 'pdf' };
    }
    return null;
  }),
}));

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

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

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

    it('should return null for undefined buffer', async () => {
      const result = await validator.detectFileType(undefined as any);
      expect(result).toBeNull();
    });

    it('should detect PNG file type from magic bytes', async () => {
      // PNG magic bytes: 89 50 4E 47 0D 0A 1A 0A
      const pngBuffer = Buffer.from([
        0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00,
        0x0d,
      ]);
      const result = await validator.detectFileType(pngBuffer);
      expect(result).not.toBeNull();
      expect(result?.mime).toBe('image/png');
    });

    it('should detect JPEG file type from magic bytes', async () => {
      // JPEG magic bytes: FF D8 FF
      const jpegBuffer = Buffer.from([0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10]);
      const result = await validator.detectFileType(jpegBuffer);
      expect(result).not.toBeNull();
      expect(result?.mime).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 = Buffer.from([0x25, 0x50, 0x44, 0x46, 0x2d, 0x31]);
      const result = await validator.detectFileType(pdfBuffer);
      expect(result).not.toBeNull();
      expect(result?.mime).toBe('application/pdf');
    });

    it('should return null for unrecognized file type', async () => {
      const unknownBuffer = Buffer.from([0x00, 0x01, 0x02, 0x03]);
      const result = await validator.detectFileType(unknownBuffer);
      expect(result).toBeNull();
    });
  });

  describe('validateMimeType', () => {
    it('should return error for empty buffer', async () => {
      const result = await validator.validateMimeType(
        Buffer.alloc(0),
        'image/png'
      );
      expect(result.isValid).toBe(false);
      expect(result.error).toContain('empty or corrupted');
    });

    it('should return error for unrecognized file type', async () => {
      const unknownBuffer = Buffer.from([0x00, 0x01, 0x02, 0x03]);
      const result = await validator.validateMimeType(
        unknownBuffer,
        'image/png'
      );
      expect(result.isValid).toBe(false);
      expect(result.error).toContain('Unable to detect');
    });

    it('should validate matching MIME types', async () => {
      const pngBuffer = Buffer.from([
        0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00,
        0x0d,
      ]);
      const result = await validator.validateMimeType(pngBuffer, '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 = Buffer.from([
        0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00,
        0x0d,
      ]);
      const result = await validator.validateMimeType(pngBuffer, 'image/jpeg');
      expect(result.isValid).toBe(false);
      expect(result.detectedMime).toBe('image/png');
      expect(result.error).toContain('MIME mismatch');
      expect(result.error).toContain('image/jpeg');
      expect(result.error).toContain('image/png');
    });
  });

  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 = Buffer.from([
        0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00,
        0x0d,
      ]);
      const result = await validator.validateUpload(pngBuffer, 'image/png', {
        allowedMimeTypes: ['image/png', 'image/jpeg'],
      });
      expect(result.isValid).toBe(true);
    });

    it('should reject MIME type mismatch', async () => {
      const pngBuffer = Buffer.from([
        0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00,
        0x0d,
      ]);
      const result = await validator.validateUpload(pngBuffer, 'image/jpeg', {
        allowedMimeTypes: ['image/png', 'image/jpeg'],
      });
      expect(result.isValid).toBe(false);
      expect(result.error).toContain('MIME mismatch');
    });

    it('should reject MIME type not in allowed list', async () => {
      const pngBuffer = Buffer.from([
        0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00,
        0x0d,
      ]);
      const result = await validator.validateUpload(pngBuffer, 'image/png', {
        allowedMimeTypes: ['image/jpeg', 'application/pdf'],
      });
      expect(result.isValid).toBe(false);
      expect(result.error).toContain('not allowed');
    });
  });
});
