import type { HttpContext } from '@adonisjs/core/http'
import drive from '@adonisjs/drive/services/main'
import logger from '@adonisjs/core/services/logger'
import { randomUUID } from 'node:crypto'
import { extname } from 'node:path'
import { Jimp } from 'jimp'
import fs from 'node:fs/promises'

const allowedExtnames = ['jpg', 'jpeg', 'png', 'webp', 'gif']

const imageMimeByExt: Record<string, string> = {
  '.jpg': 'image/jpeg',
  '.jpeg': 'image/jpeg',
  '.png': 'image/png',
  '.webp': 'image/webp',
  '.gif': 'image/gif',
}

export default class ImagesController {
  async upload({ request, response }: HttpContext) {
    const image = request.file('image', {
      size: '10mb',
      extnames: allowedExtnames,
    })

    if (!image) {
      return response.badRequest({ message: 'Image file is required' })
    }

    if (!image.isValid) {
      const message = image.errors.map((error) => error.message).join(', ')
      return response.badRequest({ message: message || 'Invalid image file' })
    }

    const extension = image.extname || 'bin'
    const filename = `${randomUUID()}.${extension}`

    await drive.use().put(filename, await fs.readFile(image.tmpPath!))

    // Generate thumbnail
    try {
      const jimpImage = await Jimp.read(image.tmpPath!)
      const buffer = await jimpImage
        .resize({ w: 200 }) // Resize to width 200px, maintain aspect ratio
        .getBuffer('image/jpeg')

      await drive.use().put(`thumbnails/${filename}`, buffer)
    } catch (error) {
      logger.error('Thumbnail generation failed: %s', error.message)
      // We don't fail the upload if thumbnail generation fails, but we log it
    }

    return response.ok({
      filename,
      url: `/api/images/${filename}`,
      thumbnailUrl: `/api/images/${filename}?type=thumbnail`,
    })
  }

  async show({ params, request, response }: HttpContext) {
    const filename = String(params.filename || '')
    const type = request.input('type')

    if (!filename || filename.includes('/') || filename.includes('\\')) {
      return response.badRequest({ message: 'Invalid image name' })
    }

    let key = filename

    if (type === 'thumbnail') {
      const thumbnailKey = `thumbnails/${filename}`
      if (await drive.use().exists(thumbnailKey)) {
        key = thumbnailKey
      }
    }

    if (!(await drive.use().exists(key))) {
      return response.notFound({ message: 'Image not found' })
    }

    const mimeType = imageMimeByExt[extname(filename).toLowerCase()] || 'application/octet-stream'
    response.header('Content-Type', mimeType)
    response.header('Cache-Control', 'public, max-age=86400')

    return response.stream(await drive.use().getStream(key))
  }

  async list() {
    const { objects } = await drive.use().listAll('')
    const images = []

    for (const file of objects) {
      if (file.isFile) {
        images.push({
          filename: file.key,
          url: `/api/images/${file.key}`,
          thumbnailUrl: `/api/images/${file.key}?type=thumbnail`,
        })
      }
    }

    return images
  }
  async delete() {

  }
}
