import fs from 'fs/promises'
import { writeFile } from 'node:fs/promises'


import sharp from 'sharp'
import { Server } from 'socket.io'

import { gameMasterLogger } from '#application/logger'
import prisma from '#application/prisma'
import { getPublicPath } from '#application/storage'
import { TSocket } from '#application/types'
import characterRepository from '#repositories/characterRepository'

interface IObjectData {
  [key: string]: Buffer
}

export default class ObjectUploadEvent {
  constructor(
    private readonly io: Server,
    private readonly socket: TSocket
  ) {}

  public listen(): void {
    this.socket.on('gm:object:upload', this.handleObjectUpload.bind(this))
  }

  private async handleObjectUpload(data: IObjectData, callback: (response: boolean) => void): Promise<void> {
    try {
      const character = await characterRepository.getById(this.socket.characterId as number)
      if (!character) return callback(false)

      if (character.role !== 'gm') {
        return callback(false)
      }
      const public_folder = getPublicPath('objects')

      // Ensure the folder exists
      await fs.mkdir(public_folder, { recursive: true })

      const uploadPromises = Object.entries(data).map(async ([key, objectData]) => {
        // Get image dimensions
        const metadata = await sharp(objectData).metadata()
        const width = metadata.width || 0
        const height = metadata.height || 0

        const object = await prisma.object.create({
          data: {
            name: key,
            tags: [],
            originX: 0,
            originY: 0,
            frameWidth: width,
            frameHeight: height
          }
        })

        const uuid = object.id
        const filename = `${uuid}.png`
        const finalFilePath = getPublicPath('objects', filename)
        await writeFile(finalFilePath, objectData)

        gameMasterLogger.info('gm:object:upload', `Object ${key} uploaded with id ${uuid}`)
      })

      await Promise.all(uploadPromises)

      callback(true)
    } catch (error: any) {
      gameMasterLogger.error('gm:object:upload error', error.message)
      callback(false)
    }
  }
}