<template>
  <Scene name="effects" @preload="preloadScene" @create="createScene" @update="updateScene" />
</template>

<script setup lang="ts">
import { Scene } from 'phavuer'
import { useZoneStore } from '@/stores/zoneStore'
import { useGameStore } from '@/stores/gameStore'
import { onBeforeUnmount, onMounted, ref, watch } from 'vue'
import type { WeatherState } from '@/types'

// Constants
const LIGHT_CONFIG = {
  SUNRISE_HOUR: 6,
  SUNSET_HOUR: 20,
  DAY_STRENGTH: 100,
  NIGHT_STRENGTH: 30
}

// Stores and refs
const gameStore = useGameStore()
const zoneStore = useZoneStore()
const sceneRef = ref<Phaser.Scene | null>(null)

// Effect objects
const effects = {
  light: ref<Phaser.GameObjects.Graphics | null>(null),
  rain: ref<Phaser.GameObjects.Particles.ParticleEmitter | null>(null),
  fog: ref<Phaser.GameObjects.Sprite | null>(null)
}

// Weather state
const weatherState = ref<WeatherState>({
  isRainEnabled: false,
  rainPercentage: 0,
  isFogEnabled: false,
  fogDensity: 0
})

// Scene setup
const preloadScene = (scene: Phaser.Scene) => {
  scene.load.image('raindrop', 'assets/raindrop.png')
  scene.load.image('fog', 'assets/fog.png')
}

const createScene = (scene: Phaser.Scene) => {
  sceneRef.value = scene
  initializeEffects(scene)
  setupSocketListeners()
}

const initializeEffects = (scene: Phaser.Scene) => {
  // Light
  effects.light.value = scene.add.graphics().setDepth(1000)

  // Rain
  effects.rain.value = scene.add.particles(0, 0, 'raindrop', {
    x: { min: 0, max: window.innerWidth },
    y: -50,
    quantity: 5,
    lifespan: 2000,
    speedY: { min: 300, max: 500 },
    scale: { start: 0.005, end: 0.005 },
    alpha: { start: 0.5, end: 0 },
    blendMode: 'ADD'
  }).setDepth(900)
  effects.rain.value.stop()

  // Fog
  effects.fog.value = scene.add.sprite(window.innerWidth / 2, window.innerHeight / 2, 'fog')
    .setScale(2)
    .setAlpha(0)
    .setDepth(950)
}

// Effect updates
const updateScene = () => {
  const timeBasedLight = calculateLightStrength(gameStore.world.date)
  const zoneEffects = zoneStore.zone?.zoneEffects as Array<{ effect: string, strength: number }>

  if (zoneEffects?.length) {
    applyEffects(zoneEffects)
  } else {
    applyEffects({
      light: timeBasedLight,
      rain: weatherState.value.isRainEnabled ? weatherState.value.rainPercentage : 0,
      fog: weatherState.value.isFogEnabled ? weatherState.value.fogDensity * 100 : 0
    })
  }
}

const applyEffects = (effectValues: any) => {
  if (effects.light.value) {
    const darkness = 1 - (effectValues.light ?? 100) / 100
    effects.light.value.clear()
      .fillStyle(0x000000, darkness)
      .fillRect(0, 0, window.innerWidth, window.innerHeight)
  }

  if (effects.rain.value) {
    const strength = effectValues.rain ?? 0
    strength > 0
      ? effects.rain.value.start().setQuantity(Math.floor((strength / 100) * 10))
      : effects.rain.value.stop()
  }

  if (effects.fog.value) {
    effects.fog.value.setAlpha((effectValues.fog ?? 0) / 100)
  }
}

const calculateLightStrength = (time: Date): number => {
  const hour = time.getHours()
  const minute = time.getMinutes()

  if (hour >= LIGHT_CONFIG.SUNSET_HOUR || hour < LIGHT_CONFIG.SUNRISE_HOUR)
    return LIGHT_CONFIG.NIGHT_STRENGTH

  if (hour > LIGHT_CONFIG.SUNRISE_HOUR && hour < LIGHT_CONFIG.SUNSET_HOUR - 2)
    return LIGHT_CONFIG.DAY_STRENGTH

  if (hour === LIGHT_CONFIG.SUNRISE_HOUR)
    return LIGHT_CONFIG.NIGHT_STRENGTH +
      ((LIGHT_CONFIG.DAY_STRENGTH - LIGHT_CONFIG.NIGHT_STRENGTH) * minute) / 60

  const totalMinutes = (hour - (LIGHT_CONFIG.SUNSET_HOUR - 2)) * 60 + minute
  return LIGHT_CONFIG.DAY_STRENGTH -
    (LIGHT_CONFIG.DAY_STRENGTH - LIGHT_CONFIG.NIGHT_STRENGTH) * (totalMinutes / 120)
}

// Socket and window handlers
const setupSocketListeners = () => {
  gameStore.connection?.emit('weather', (response: WeatherState) => {
    weatherState.value = response
    updateScene()
  })

  gameStore.connection?.on('weather', (data: WeatherState) => {
    weatherState.value = data
    updateScene()
  })

  gameStore.connection?.on('date', updateScene)
}

const handleResize = () => {
  if (effects.rain.value)
    effects.rain.value.updateConfig({ x: { min: 0, max: window.innerWidth } })
  if (effects.fog.value)
    effects.fog.value.setPosition(window.innerWidth / 2, window.innerHeight / 2)
}

// Lifecycle
watch(() => zoneStore.zone?.zoneEffects, updateScene, { deep: true })

onMounted(() => window.addEventListener('resize', handleResize))

onBeforeUnmount(() => {
  window.removeEventListener('resize', handleResize)
  if (sceneRef.value) sceneRef.value.scene.remove('effects')
  gameStore.connection?.off('weather')
})
</script>