// src/utils/fileUtils.test.ts
import { describe, it, expect, vi, beforeEach, Mocked } from 'vitest';
import fs from 'node:fs/promises';
import { logger } from '../services/logger.server';
import { cleanupUploadedFile, cleanupUploadedFiles } from './fileUtils';

// Mock dependencies
vi.mock('node:fs/promises', () => ({
  default: {
    unlink: vi.fn(),
  },
}));

vi.mock('../services/logger.server', () => ({
  logger: {
    warn: vi.fn(),
  },
}));

// Cast the mocked imports for type safety
const mockedFs = fs as Mocked<typeof fs>;
const mockedLogger = logger as Mocked<typeof logger>;

describe('fileUtils', () => {
  beforeEach(() => {
    // Clear mock history before each test
    vi.clearAllMocks();
  });

  describe('cleanupUploadedFile', () => {
    it('should call fs.unlink with the correct file path', async () => {
      const mockFile = { path: '/tmp/test-file.jpg' } as Express.Multer.File;
      mockedFs.unlink.mockResolvedValue(undefined);

      await cleanupUploadedFile(mockFile);

      expect(mockedFs.unlink).toHaveBeenCalledWith('/tmp/test-file.jpg');
    });

    it('should not call fs.unlink if the file is undefined', async () => {
      await cleanupUploadedFile(undefined);
      expect(mockedFs.unlink).not.toHaveBeenCalled();
    });

    it('should log a warning and not throw if fs.unlink fails', async () => {
      const mockFile = { path: '/tmp/non-existent-file.jpg' } as Express.Multer.File;
      const unlinkError = new Error('ENOENT: no such file or directory');
      mockedFs.unlink.mockRejectedValue(unlinkError);

      // Use a try-catch to ensure no error is thrown from the function itself
      let didThrow = false;
      try {
        await cleanupUploadedFile(mockFile);
      } catch {
        didThrow = true;
      }

      expect(didThrow).toBe(false);
      expect(mockedLogger.warn).toHaveBeenCalledWith(
        { err: unlinkError, filePath: mockFile.path },
        'Failed to clean up uploaded file.',
      );
    });
  });

  describe('cleanupUploadedFiles', () => {
    const mockFiles = [
      { path: '/tmp/file1.jpg' },
      { path: '/tmp/file2.png' },
    ] as Express.Multer.File[];

    it('should call fs.unlink for each file in the array', async () => {
      mockedFs.unlink.mockResolvedValue(undefined);

      await cleanupUploadedFiles(mockFiles);

      expect(mockedFs.unlink).toHaveBeenCalledTimes(2);
      expect(mockedFs.unlink).toHaveBeenCalledWith('/tmp/file1.jpg');
      expect(mockedFs.unlink).toHaveBeenCalledWith('/tmp/file2.png');
    });

    it('should not call fs.unlink if the files array is undefined', async () => {
      await cleanupUploadedFiles(undefined);
      expect(mockedFs.unlink).not.toHaveBeenCalled();
    });

    it('should not call fs.unlink if the input is not an array', async () => {
      await cleanupUploadedFiles({ not: 'an array' } as unknown as Express.Multer.File[]);
      expect(mockedFs.unlink).not.toHaveBeenCalled();
    });

    it('should handle an empty array gracefully', async () => {
      await cleanupUploadedFiles([]);
      expect(mockedFs.unlink).not.toHaveBeenCalled();
    });
  });
});