import math
from typing import List

import pygame.draw
from coopstructs.geometry.vectors.vectorN import Vector2
from coopgame.gameTemplate import GameTemplate, BuiltInSurfaceType
from coopgame.particleSystem import Particle, Emitter, particle_destroyer, time_destroyer, InterpolateColorBehavior, ParticleGenerationArgs
import coopgame.particleSystem.recipies as recip
import random as rnd
from cooptools.colors import Color
from functools import partial
from cooptools.dataRefresher import DataRefresher
import logging
from coopgame.logger import logger
from coopgame.particleSystem import ParticleRenderer, RenderShape, PulseColorBehavior, LifetimeType
import coopgame.particleSystem.utils as utils

class ParticleGame(GameTemplate):


    def initialize_game(self):
        self.firework_launch_sound = pygame.mixer.Sound(
            "../coopgame/assets/sounds/81455__csengeri__fireworks-launch-denoised.wav")
        self.firework_explosion_sound = pygame.mixer.Sound(
            "../coopgame/assets/sounds/553153__eminyildirim__firework-single-explosion.wav")

        snow_renderer = ParticleRenderer(
            shape=RenderShape.CIRCLE,
            colorBehavior=Color.SNOW
        )
        self.snow = recip.snow(
            origin_line_start=Vector2(0,0),
            origin_line_end=Vector2(self.screen_width, 0),
            fall_velo=Vector2(0, 100),
            lifespan_ms=15000,
            size=3,
            twinkle_ms=500,
            renderer=snow_renderer,
            particle_generation_args=ParticleGenerationArgs(generation_interval_ms=100)
        )

        comet_lifespan = 1000
        comet_colors = [
                    Color.WHITE,
                    Color.PURPLE,
                    Color.ORANGE,
                    Color.BLUE,

                ]
        comet_renderer = ParticleRenderer(
            shape=RenderShape.CIRCLE,
            colorBehavior=PulseColorBehavior(
                colors=comet_colors,
                pulse_duration_ms=int(comet_lifespan/len(comet_colors))
            ),
            lifetime_type=LifetimeType.EMITTER
        )
        self.comet = recip.comet(
            path=lambda: utils.rotation(self.game_time_tracker.run_time, self.screen_height, self.screen_width),
            radiate_speed=50,
            lifespan_ms=comet_lifespan,
            start_size=5,
            renderer=comet_renderer,
            particle_generation_args=ParticleGenerationArgs(generation_interval_ms=5)
        )

        comet_lifespan = 1000
        comet_colors = [
                    Color.WHITE,
                    Color.PURPLE,
                    Color.ORANGE,
                    Color.BLUE,

                ]
        comet_renderer = ParticleRenderer(
            shape=RenderShape.CIRCLE,
            colorBehavior=PulseColorBehavior(
                colors=comet_colors,
                pulse_duration_ms=int(comet_lifespan/len(comet_colors))
            ),
            lifetime_type=LifetimeType.PARTICLE
        )
        self.comet2 = recip.comet(
            path=lambda: utils.rotation(self.game_time_tracker.run_time, self.screen_height, self.screen_width, phase=500),
            radiate_speed=50,
            lifespan_ms=comet_lifespan,
            start_size=5,
            renderer=comet_renderer,
            particle_generation_args=ParticleGenerationArgs(generation_interval_ms=5)
        )

        fire_renderer = ParticleRenderer(
            colorBehavior=InterpolateColorBehavior(start_color=Color.ORANGE, end_color=Color.PURPLE, lifespan_ms=1500)
        )
        smoke_renderer = ParticleRenderer(
            colorBehavior=InterpolateColorBehavior(start_color=Color.DARK_GRAY, end_color=Color.BLACK, lifespan_ms=5000)
        )
        self.torch = recip.torch(
            Vector2(250, 250),
            fire_lifespan_ms=1500,
            smoke_lifespan_ms=5000,
            fire_start_size=10,
            smoke_end_size=20,
            fire_raise_velo=Vector2(0, -50),
            smoke_raise_velo=Vector2(0, -15),
            fire_renderer=fire_renderer,
            smoke_renderer=smoke_renderer
        )

        fountain_particle_lifespan_ms = 2750
        fountain_renderer = ParticleRenderer(
            colorBehavior=InterpolateColorBehavior(start_color=Color.DARK_BLUE, end_color=Color.ALICE_BLUE,
                                                   lifespan_ms=fountain_particle_lifespan_ms),
            reverse=True
        )
        self.fountain = recip.fountain(
            origin=Vector2(500, 250),
            spray_intensity=150,
            spray_arc=(75, 105),
            fountain_lifespan_ms=fountain_particle_lifespan_ms,
            drop_accel=Vector2(0, 100),
            droplet_size_start=10,
            droplet_size_end=1,
            droplet_renderer=fountain_renderer,
            droplet_generation_args=ParticleGenerationArgs(generation_interval_ms=10)
        )


        f_origin = lambda: Vector2(rnd.randint(0, self.screen_width), self.screen_height)
        firework_renderer = ParticleRenderer(
            colorBehavior=InterpolateColorBehavior(start_color=lambda: Color.random(), end_color=Color.BLACK,
                                                   lifespan_ms=fountain_particle_lifespan_ms),
        )
        self.firework = recip.firework(
            origin=f_origin,
            launch_speed=lambda : rnd.randint(200, 250),
            spread=lambda: rnd.randint(650, 850),
            lifespan_ms=rnd.randint(500, 750),
            drop_accel=Vector2(0, 20),
            size_start=5,
            size_end=1,
            arms=lambda: rnd.randint(3, 20),
            explosion_renderer=firework_renderer,
            launch_renderer=ParticleRenderer(colorBehavior=Color.WHITE),
            burst_interval_ms=lambda: rnd.randint(500, 2500),
            launch_start_callback=lambda x: self.firework_launch_sound.play(),
            launch_end_callback = lambda x: self.firework_launch_sound.stop(),
            explosion_start_callback= lambda x: self.firework_explosion_sound.play(),
            explosion_end_callback=lambda x: self.firework_explosion_sound.stop(),

        )


        self.log_part_refresher = DataRefresher('log_stats',
                                                 refresh_callback=lambda: self.particle_stats(),
                                                 refresh_interval_ms=5000)

    def handle_left_mouse_down(self, pressed_keys, mouse_pos_as_vector: Vector2):
        pass

    def handle_left_mouse_up(self, pressed_keys, mouse_pos_as_vector: Vector2):
        pass

    def handle_right_mouse_down(self, pressed_keys, mouse_pos_as_vector: Vector2):
        pass

    def handle_right_mouse_up(self, pressed_keys, mouse_pos_as_vector: Vector2):
        pass

    def handle_hover_over(self, pressed_keys, mouse_pos_as_vector: Vector2):
        pass

    def handle_mouse_scroll_up(self, pressed_keys, mouse_pos_as_vector: Vector2):
        pass

    def handle_mouse_scroll_down(self, pressed_keys, mouse_pos_as_vector: Vector2):
        pass

    def draw(self, frames: int, debug_mode: bool = False):
        self.snow.render(self.screen)
        self.comet.render(self.screen)
        self.comet2.render(self.screen)
        self.torch.render(self.screen)
        self.fountain.render(self.screen)
        self.firework.render(self.screen)

    def model_updater(self, delta_time_ms: int):
        self.snow.update(delta_time_ms)
        self.comet.update(delta_time_ms)
        self.comet2.update(delta_time_ms)
        self.torch.update(delta_time_ms)
        self.fountain.update(delta_time_ms)
        self.firework.update(delta_time_ms)

        self.log_part_refresher.check_and_refresh()

    def sprite_updater(self, delta_time_ms: int):
        pass

    def on_resize(self):
        pass

    def register_keys(self):
        pass

    def update_built_in_surfaces(self, surface_types: List[BuiltInSurfaceType]):
        pass

    def particle_stats(self):
        logger.info(f"Particle Count: \n"
                    f"Snow: {self.snow.n_particles()}\n"
                     f"Comet: {self.comet.n_particles()}\n"
                     f"Torch: {self.torch.n_particles()}\n"
                    f"Fountain: {self.fountain.n_particles()}\n"
                    f"Firework: {self.firework.n_particles()}")

if __name__ == "__main__":
    game = ParticleGame()
    game.main()