import { SocketEvent } from '@/application/enums'
import Logger, { LoggerType } from '@/application/logger'
import type { TSocket } from '@/application/types'
import { Character } from '@/entities/character'
import MapManager from '@/managers/mapManager'
import type MapCharacter from '@/models/mapCharacter'
import CharacterRepository from '@/repositories/characterRepository'
import { Server } from 'socket.io'

export abstract class BaseEvent {
  protected readonly logger = Logger.type(LoggerType.GAME)
  private lastActionTimes: Map<string, number> = new Map()

  constructor(
    readonly io: Server,
    readonly socket: TSocket
  ) {}

  protected isThrottled(actionId: string, throttleTime: number): boolean {
    const now = Date.now()
    const lastActionTime = this.lastActionTimes.get(actionId) || 0

    if (now - lastActionTime < throttleTime) {
      return true
    }

    this.lastActionTimes.set(actionId, now)

    return false
  }

  protected getMapCharacter(): MapCharacter | null {
    if (!this.socket.characterId) return null
    return MapManager.getCharacterById(this.socket.characterId)
  }

  protected async getCharacter(): Promise<Character | null> {
    if (!this.socket.characterId) return null
    const characterRepository = new CharacterRepository()
    return characterRepository.getById(this.socket.characterId)
  }

  protected async isCharacterGM(): Promise<boolean> {
    const character = await this.getCharacter()
    return character?.getRole() === 'gm'
  }

  protected sendNotificationAndLog(message: string): void {
    this.socket.emit(SocketEvent.NOTIFICATION, { title: 'Server message', message })
    this.logger.error('Base event error', `Player ${this.socket.userId}: ${message}`)
  }

  protected handleError(context: string, error: unknown): void {
    console.log(error)
    const errorMessage = error instanceof Error ? error.message : error && typeof error === 'object' && 'toString' in error ? error.toString() : String(error)
    this.socket.emit(SocketEvent.NOTIFICATION, { title: 'Server message', message: `Server error occured. Please contact the server administrator.` })
    this.logger.error('Base event error', errorMessage)
  }
}