/* eslint-disable @typescript-eslint/no-var-requires */
import {MediaType} from '@modules/chats/interfaces';

jest.mock('react-native-compressor', () => ({
  Image: {
    compress: jest.fn(),
  },
  Video: {
    compress: jest.fn(),
  },
  createVideoThumbnail: jest.fn(),
  getImageMetaData: jest.fn(),
  getVideoMetaData: jest.fn(),
}));

const mockGetAuthHeader = jest.fn();
const mockGetAccessToken = jest.fn();

jest.mock('@config/api', () => ({
  getAuthHeader: mockGetAuthHeader,
}));

jest.mock('@config/tokens', () => ({
  tokenManager: {
    getAccessToken: mockGetAccessToken,
  },
}));

jest.mock('@shared/utils', () => ({
  getUlid: jest.fn(),
}));

let mockImageCompress: jest.Mock;
let mockVideoCompress: jest.Mock;
let mockHumandVideoCompress: jest.Mock;
let mockCreateVideoThumbnail: jest.Mock;
let mockGetImageMetaData: jest.Mock;
let mockGetVideoMetaData: jest.Mock;
let mockGetUlid: jest.Mock;

let compressImage: typeof import('../compression').compressImage;
let compressVideo: typeof import('../compression').compressVideo;
let generateThumbnailUrl: typeof import('../compression').generateThumbnailUrl;

describe('compression utils', () => {
  beforeEach(() => {
    jest.resetModules();
    const compressorMock = jest.requireMock('react-native-compressor');
    mockImageCompress = compressorMock.Image.compress as jest.Mock;
    mockVideoCompress = compressorMock.Video.compress as jest.Mock;
    mockCreateVideoThumbnail = compressorMock.createVideoThumbnail as jest.Mock;
    mockGetImageMetaData = compressorMock.getImageMetaData as jest.Mock;
    mockGetVideoMetaData = compressorMock.getVideoMetaData as jest.Mock;
    mockGetUlid = jest.requireMock('@shared/utils').getUlid as jest.Mock;
    mockImageCompress.mockReset();
    mockVideoCompress.mockReset();
    mockCreateVideoThumbnail.mockReset();
    mockGetImageMetaData.mockReset();
    mockGetVideoMetaData.mockReset();
    mockGetAuthHeader.mockReset();
    mockGetAccessToken.mockReset();
    mockGetUlid.mockReset();

    jest.isolateModules(() => {
      const compression =
        require('../compression') as typeof import('../compression');
      ({compressImage, compressVideo, generateThumbnailUrl} = compression);
      mockHumandVideoCompress = (
        require('@native-modules/expo-humand-media-handler') as {
          default: {compressVideo: jest.Mock};
        }
      ).default.compressVideo;
    });
  });

  it('compresses images and builds media entity', async () => {
    mockGetUlid.mockReturnValue('media-1');
    mockImageCompress.mockResolvedValue('file://compressed.jpg');
    mockGetImageMetaData.mockResolvedValue({
      ImageHeight: 400,
      ImageWidth: 300,
      size: 1024,
    });

    const media = await compressImage('file://original.jpg', 'photo.jpg');

    expect(mockImageCompress).toHaveBeenCalledWith('file://original.jpg', {
      maxWidth: 1280,
      maxHeight: 1280,
      quality: 0.8,
      output: 'jpg',
    });
    expect(mockGetImageMetaData).toHaveBeenCalledWith('file://compressed.jpg');
    expect(media).toEqual({
      id: 'media-1',
      type: MediaType.IMAGE,
      fileAsset: null,
      status: 'creatingAsset',
      contentType: 'image/jpeg',
      localUri: 'file://compressed.jpg',
      height: 400,
      width: 300,
      sizeInBytes: 1024,
      name: 'photo.jpg',
    });
  });

  it('creates thumbnail without headers for local paths', async () => {
    mockCreateVideoThumbnail.mockResolvedValue({
      path: 'file://thumb-local.jpg',
    });

    const result = await generateThumbnailUrl('file://video.mp4');

    expect(mockGetAccessToken).not.toHaveBeenCalled();
    expect(mockCreateVideoThumbnail).toHaveBeenCalledWith(
      'file://video.mp4',
      undefined,
    );
    expect(result).toBe('file://thumb-local.jpg');
  });

  it('returns null when thumbnail generation fails', async () => {
    mockCreateVideoThumbnail.mockRejectedValue(new Error('boom'));

    const result = await generateThumbnailUrl('file://video.mp4');

    expect(result).toBeNull();
  });

  it('compresses videos and updates media metadata', async () => {
    mockHumandVideoCompress.mockResolvedValue('file://compressed.mp4');
    mockGetVideoMetaData.mockResolvedValue({
      height: 720,
      width: 1280,
      size: 2048,
    });

    const media = await compressVideo({
      id: 'media-2',
      type: MediaType.VIDEO,
      fileAsset: null,
      status: 'idle',
      contentType: 'video/mp4',
      localUri: 'file://original.mp4',
      name: 'video.mp4',
      sizeInBytes: 1000,
    });

    expect(mockHumandVideoCompress).toHaveBeenCalledWith(
      'file://original.mp4',
      {
        maxSize: 1280,
        bitrate: 2140000,
      },
    );
    expect(mockGetVideoMetaData).toHaveBeenCalledWith('file://compressed.mp4');
    expect(media).toEqual({
      id: 'media-2',
      type: MediaType.VIDEO,
      fileAsset: null,
      status: 'idle',
      contentType: 'video/mp4',
      localUri: 'file://compressed.mp4',
      name: 'video.mp4',
      sizeInBytes: 2048,
      height: 720,
      width: 1280,
    });
  });
});
