import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
import fs from 'node:fs'
import path from 'node:path'
import { persistMultipartImages } from '../upload-images.js'

const UPLOADS_DIR = path.join(process.cwd(), 'uploads')
const TEST_PREFIX = 'upload-test-'

describe('persistMultipartImages with eager mode', () => {
  afterEach(async () => {
    const files = await fs.promises.readdir(UPLOADS_DIR).catch(() => [])
    for (const file of files) {
      if (file.startsWith(TEST_PREFIX)) {
        await fs.promises.unlink(path.join(UPLOADS_DIR, file)).catch(() => {})
      }
    }
    const cacheDir = path.join(UPLOADS_DIR, '.cache')
    await fs.promises.rm(cacheDir, { recursive: true, force: true }).catch(() => {})
  })

  it('returns WebP URLs when eager=true', async () => {
    const sharp = (await import('sharp')).default
    const testImagePath = path.join(UPLOADS_DIR, `${TEST_PREFIX}original.png`)
    await sharp({ create: { width: 100, height: 100, channels: 3, background: { r: 255, g: 0, b: 0 } } })
      .png()
      .toFile(testImagePath)

    const filesBefore = await fs.promises.readdir(UPLOADS_DIR)

    const mockRequest = {
      isMultipart: () => true,
      parts: async function* () {
        const buffer = await fs.promises.readFile(testImagePath)
        yield {
          file: true,
          filename: 'test.png',
          toBuffer: async () => buffer,
        }
      },
    }

    const urls = await persistMultipartImages(mockRequest, {
      maxFiles: 1,
      maxFileBytes: 20 * 1024 * 1024,
      subdir: '',
      eager: true,
    })

    expect(urls).toHaveLength(1)
    expect(urls[0]).toMatch(/\/uploads\/[a-f0-9-]+\.webp$/)

    // Verify the intermediate PNG file written by persistMultipartImages was deleted
    const filesAfter = await fs.promises.readdir(UPLOADS_DIR)
    const newPngFiles = filesAfter.filter((f) => !filesBefore.includes(f) && f.endsWith('.png'))
    expect(newPngFiles).toHaveLength(0)
  })

  it('returns original format URLs when eager=false', async () => {
    const sharp = (await import('sharp')).default
    const testImagePath = path.join(UPLOADS_DIR, `${TEST_PREFIX}original2.png`)
    await sharp({ create: { width: 100, height: 100, channels: 3, background: { r: 0, g: 255, b: 0 } } })
      .png()
      .toFile(testImagePath)

    const mockRequest = {
      isMultipart: () => true,
      parts: async function* () {
        const buffer = await fs.promises.readFile(testImagePath)
        yield {
          file: true,
          filename: 'test.png',
          toBuffer: async () => buffer,
        }
      },
    }

    const urls = await persistMultipartImages(mockRequest, {
      maxFiles: 1,
      maxFileBytes: 20 * 1024 * 1024,
      subdir: '',
      eager: false,
    })

    expect(urls).toHaveLength(1)
    expect(urls[0]).toMatch(/\/uploads\/[a-f0-9-]+\.png$/)
  })

  it('cleans up original file on eager processing error', async () => {
    const invalidBuffer = Buffer.from('not an image')

    const filesBefore = await fs.promises.readdir(UPLOADS_DIR)

    const mockRequest = {
      isMultipart: () => true,
      parts: async function* () {
        yield {
          file: true,
          filename: 'test.png',
          toBuffer: async () => invalidBuffer,
        }
      },
    }

    await expect(
      persistMultipartImages(mockRequest, {
        maxFiles: 1,
        maxFileBytes: 20 * 1024 * 1024,
        subdir: '',
        eager: true,
      }),
    ).rejects.toThrow()

    // The intermediate file written by persistMultipartImages should be cleaned up
    const filesAfter = await fs.promises.readdir(UPLOADS_DIR)
    const newFiles = filesAfter.filter((f) => !filesBefore.includes(f) && f !== '.cache')
    expect(newFiles).toHaveLength(0)
  })
})
