import pygame
from typing import Tuple
from coopgame.gameTemplate import GameTemplate
import coopgame.pointdrawing.point_draw_utils as pdu
import coopgame.pygamehelpers as phelp
from cooptools.colors import Color
import logging
import coopgame.handleKeyPressedArgs as kpa
from cooptools.toggles import BooleanToggleable
import coopgame.characterDevelopment.character as char
import coopgame.characterDevelopment.stats as stat
import coopgame.label_drawing.label_drawing_utils as ldu
from coopgame.characterDevelopment.manifests import MutuallyExclusiveManifest
from coopgame.characterDevelopment.behaviorExtensions import hp as hp
from coopgame.characterDevelopment.behaviorExtensions import dual as dual

class CharDevTestGame(GameTemplate):

    def __init__(self):
        self.show_stats_toggle = BooleanToggleable(default=True)
        self.show_dual_toggle = BooleanToggleable(default=False)

        super().__init__(
            input_state_handler=self.define_input_handler()
        )
        self.char: char.Character = None
        self.stats_surf: pygame.Surface = None
        self.dual_surf: pygame.Surface = None
        self.last_char: char.Character = None

        self.reset_char()

    def reset_char(self):
        self.last_char = self.char
        self.char = self.gen_char()

        self.build_stats_surface(char=self.char)

    def build_stats_surface(self,
                            char: char.Character):
        surf = phelp.init_surface(self.screen.get_size())
        surf.fill(color=Color.BEIGE.value)
        self.stats_surf = self.print_char_stats_to_surface(char, surf=surf)

    def build_dualing_surface(self,
                              dualist1: char.Character,
                              dualist2: char.Character):
        surf = phelp.init_surface(self.screen.get_size())
        surf.fill(color=Color.ORANGE.value)
        self.print_dualing_stats_to_surface(surf, dualist1, dualist2)
        return surf


    def draw(self, frames: int, debug_mode: bool = False):
        pdu.draw_points(
            points={
                (self.ScreenCenter): pdu.DrawPointArgs(
                    color=Color.BLUE,
                    outline_color=Color.ORANGE,
                    radius=50,
                    outline_width=4
                )
            },
            surface=self.screen
        )
        phelp.draw_arrow(self.screen,
                        self.ScreenCenter,
                        phelp.mouse_pos_as_vector().as_tuple(),
                        Color.GREEN,
                         leader_line=True)
        if self.show_stats_toggle.value:
            self.screen.blit(self.stats_surf, (0, 0))

    def define_input_handler(self):
        return kpa.InputStateHandler(
            quit_callback_package=kpa.CallbackPackage(down=lambda x: self.quit()),
            debug_callback_package=kpa.CallbackPackage(down=lambda x: self.debug_mode_toggle.toggle()),
            fullscreen_callback_package=kpa.CallbackPackage(down=lambda x: self.toggle_fullscreen()),
            key_actions=[
                kpa.InputAction([kpa.InputEvent(kpa.PyKeys.K_s)], callback=lambda x: self.show_stats_toggle.toggle()),
                kpa.InputAction([kpa.InputEvent(kpa.PyKeys.K_r)], callback=lambda x: self.reset_char()),
                kpa.InputAction([kpa.InputEvent(kpa.PyKeys.K_d)], callback=lambda x: self.dual()),
        ])

    def gen_char(self) -> char.Character:
        config_fn_provider = r'C:\Users\Tj Burns\PycharmProjects\coopgame\coopgame\characterDevelopment\manifest.json'

        names = MutuallyExclusiveManifest.from_config(config_file_name_provider=config_fn_provider, key='names')

        me = char.Character.generate(
            args=char.CharacterGeneratorArgs(
                name_provider=lambda x: names.random(type=x)[1],
                init_stats_package=stat.StatsPackageState.from_config(config_fn_provider),
                traits_manifest=stat.StatEffectPackageManifest.from_config_data(config_fn_provider)
            ),
            trait_count_args={
                "personality_traits": 3,
                "physical_traits": 2,
                "race": 1,
                "skills": 1
            }
        )
        return me

    def _dual_epoch_handler(self,
                            dualist1: char.Character,
                            dualist2: char.Character,
                            ) -> Tuple[char.Character, char.Character]:
        d1, d2 = dual.basic_dualing_epoch_handler(dualist1, dualist2)



        return d1, d2

    def dual(self):



        if self.last_char is not None:
            dual.dual(self.char, self.last_char, dual.basic_dualing_epoch_handler)



    def print_char_stats_to_surface(self,
                                    character: char.Character,
                                    surf: pygame.Surface) -> pygame.Surface:
        stats = character.stats.State.Summary

        header_font = pygame.font.SysFont(name='Comic Sans MS', size=24)
        header_font.set_underline(True)
        regular_font = pygame.font.SysFont(name='Comic Sans MS', size=12)

        ldu.draw_label(
            hud=surf,
            args=ldu.LabelArgs(
                draw_args=ldu.DrawLabelArgs(
                color=Color.BLACK,
                font=header_font,
                ),
                text=f"Stats Page",
                pos=(50, 15)
            )
        )

        n_stats = len(stats['base_stats'])
        stat_per_col = n_stats // 2

        ldu.draw_label(hud=surf,
                       args=ldu.LabelArgs(
                           text=f"Character Name: {character.name}",
                        draw_args=ldu.DrawLabelArgs(
                           color=Color.BLACK,
                           font=regular_font),
                       pos=(100, 50)
                       )
                       )


        ldu.draw_label(
            hud=surf,
            args=ldu.LabelArgs(
                text=f"Race: {character.Race.id}",
                draw_args=ldu.DrawLabelArgs(
                    color=Color.BLACK,
                    font=regular_font
                ),
                pos=(100, 60))
        )


        ii = 0
        row_offset = 15
        col_offset = 250
        for stat, val in stats['base_stats'].items():
            new_txt = f"{stat}: {val} ({stats['internally_resolved_stats'][stat]})"
            pos = (
                125 if ii < stat_per_col else 125 + col_offset,
                100 + ii * row_offset if ii < stat_per_col else 100 + (ii - stat_per_col) * row_offset
            )

            ldu.draw_label(hud=surf,
                           args=ldu.LabelArgs(
                               text=new_txt,
                               draw_args=ldu.DrawLabelArgs(
                                   color=Color.BLACK,
                                   font=regular_font
                               ),
                               pos=pos)
                           )

            ii+=1

        ii = 0
        for mod in stats['stat_modifiers']:
            lamb = lambda x: f"{x['stat_name']}: {x['delta_effect']}"
            new_txt = f"{mod['id']} [{','.join([lamb(x) for x in mod['stat_effects']])}]"
            pos = (
                125,
                300 + ii * row_offset
            )

            ldu.draw_label(hud=surf,
                           args=ldu.LabelArgs(
                               text=new_txt,
                               draw_args=ldu.DrawLabelArgs(
                                   color=Color.BLACK,
                                   font=regular_font
                               ),
                               pos=pos)
                           )

            ii+=1

        if self.last_char is not None:
            opinion = self.char.opinon_of(self.last_char)
            ldu.draw_label(hud=surf,
                           args=ldu.LabelArgs(
                               text=f"Opinion of {self.last_char.name}: {opinion.Score}",
                               draw_args=ldu.DrawLabelArgs(
                                   color=Color.BLACK,
                                   font=regular_font
                               ),
                               pos=(700, 75))
                           )


            x_start = 725
            y_start = 90
            ii=0
            for stat, val in opinion.factors.items():
                new_txt = f"{stat}: {val}"
                pos = (
                    x_start,
                    y_start + ii * row_offset
                )

                ldu.draw_label(hud=surf,
                               args=ldu.LabelArgs(
                                   text=new_txt,
                                   draw_args=ldu.DrawLabelArgs(
                                       color=Color.BLACK,
                                       font=regular_font
                                   ),
                                   pos=pos)
                               )

                ii += 1

        return surf

    def _get_font(self,
                  underlined: bool = False,
                  size: int = 12,
                  name: str = 'Comic Sans MS'):
        ret = pygame.font.SysFont(name=name, size=size)
        if underlined:
            ret.set_underline(True)
        return ret


    def print_dualing_stats_to_surface(self,
                                        surf: pygame.Surface,
                                        dualist1: char.Character,
                                        dualist2:char.Character,

    ):
        header_font = self._get_font(underlined=True, size=24)
        regular_font = self._get_font()

        # draw header
        ldu.draw_label(hud=surf,
                       args=ldu.LabelArgs(
                           text=f"DUAL!!",
                           draw_args=ldu.DrawLabelArgs(
                               font=header_font,
                               color=Color.BLACK
                           ),
                           pos=(50, 15))
                       )


        # draw dualist 1
        ldu.draw_label(hud=surf,
                       args=ldu.LabelArgs(
                           text=f"Character Name: {dualist1.name}",
                           draw_args=ldu.DrawLabelArgs(
                               color=Color.BLACK,
                               font=regular_font
                           ),
                           pos=(100, 50))
                       )


        health = dualist1.stats.State.resolve_stat(stat_name=hp.HP)
        ldu.draw_label(hud=surf,
                       args=ldu.LabelArgs(
                           text=f"Hp: {health}",
                           draw_args=ldu.DrawLabelArgs(
                               color=Color.BLACK,
                               font=regular_font
                           ),
                           pos=(100, 60))
                       )


        # draw dualist 1
        ldu.draw_label(hud=surf,
                       args=ldu.LabelArgs(
                           text=f"Character Name: {dualist2.name}",
                           draw_args=ldu.DrawLabelArgs(
                               color=Color.BLACK,
                               font=regular_font
                           ),
                           pos=(600, 50))
                       )


        health = dualist2.stats.State.resolve_stat(stat_name=hp.HP)
        ldu.draw_label(hud=surf,
                       args=ldu.LabelArgs(
                           text=f"Hp: {health}",
                           draw_args=ldu.DrawLabelArgs(
                               color=Color.BLACK,
                               font=regular_font
                           ),
                           pos=(600, 60))

                       )

    # def print_details_to_surface(self,
    #                             surf: pygame.Surface,
    #                             text: str,
    #                             draw_label_args: ldu.DrawLabelArgs):



logging.basicConfig(level=logging.INFO)
logging.getLogger('cooptools.CommandController').setLevel(logging.WARN)
g = CharDevTestGame()
g.main()