import pygame
import pygame_gui
from enum import Enum, auto
from random import randint
from functions import *


class Player:
    """Character Creation"""

    # Default Character
    def __init__(self, name, gender, age, race, job):
        # Personality
        self.name = name
        self.gender = gender
        self.age = age
        self.race = race
        self.job = job
        # Health
        self.currentHP = 100
        self.maxHP = 100
        # Levels
        self.level = 1
        self.exp = 0
        self.maxEXP = 100
        # Magic
        self.spells_known = []
        self.spells_ready = []
        # Equipment
        self.weapon = rock
        self.armor = tornRags
        # Defence
        self.ac = 0
        self.elemental_resistance = {DamageType.FIRE: False, DamageType.WATER: False, DamageType.LIGHTNING: False}
        self.physical_resistance = {DamageType.SLASHING: False, DamageType.CRUSHING: False, DamageType.PIERCING: False}
        # Ability Scores
        self.stats = {"Strength": 0,
                      "Dexterity": 0,
                      "Constitution": 0,
                      "Intelligence": 0,
                      "Wisdom": 0,
                      "Charisma": 0}
        # Ability Modifiers
        self.mods = {"Strength": 0,
                     "Dexterity": 0,
                     "Constitution": 0,
                     "Intelligence": 0,
                     "Wisdom": 0,
                     "Charisma": 0}
        # Held items
        self.inventory = {rock: {"Count": 1,
                                 "object": Weapon,
                                 "equipped": True
                                 },
                          tornRags: {"Count": 1,
                                     "object": Armor,
                                     "equipped": True
                                     },
                          GP1: {"Count": 10,
                                "object": Money,
                                "equipped": False
                                },
                          }

    # @property
    # def dexMod(self):
    #     return self.mods["Dexterity"]

    def getModifier(self):
        self.mods["Strength"] = -5 + self.stats["Strength"] // 2
        self.mods["Dexterity"] = -5 + self.stats["Dexterity"] // 2
        self.mods["Constitution"] = -5 + self.stats["Constitution"] // 2
        self.mods["Intelligence"] = -5 + self.stats["Intelligence"] // 2
        self.mods["Wisdom"] = -5 + self.stats["Wisdom"] // 2
        self.mods["Charisma"] = -5 + self.stats["Charisma"] // 2

    def set_stats(self):
        if self.race == "elf":
            self.stats["Dexterity"] += 2
            self.stats["Intelligence"] += 2
        elif self.race == "human":
            self.stats["Strength"] += 2
            self.stats["Constitution"] += 2
        elif self.race == "dwarf":
            self.stats["Constitution"] += 2
            self.stats["Strength"] += 2
        elif self.job == "warrior":
            self.stats["Strength"] += 2
            self.stats["Constitution"] += 1
        elif self.job == "ranger":
            self.stats["Dexterity"] += 2
            self.stats["Charisma"] += 1
        elif self.job == "mage":
            self.stats["Intelligence"] += 2
            self.stats["Charisma"] += 1

    def introduce(self):
        typingPrint("Adjusting for your race and class bonuses." + "\n", time)
        time.sleep(1)
        typingPrint(f'Welcome {self.name}, to Kanjin: An RPG Text Adventure.\n', time)

    def current_stats(self):
        """Prints a display of the user's current statistics."""
        print("Your current stats are:")
        print(f'Hit Points: {self.currentHP}/{self.maxHP}')
        print(f'Strength: {self.stats["Strength"]}')
        print(f'Dexterity: {self.stats["Dexterity"]}')
        print(f'Constitution: {self.stats["Constitution"]}')
        print(f'Intelligence: {self.stats["Intelligence"]}')
        print(f'Charisma: {self.stats["Charisma"]}')

    def current_equip(self):
        """Prints a list of items currently equipped."""
        typingPrint(f"You have equipped:<br> {self.armor.name}<br>"
                    f"    {self.armor.description}"
                    f"<br>{self.weapon.name}<br>"
                    f"    {self.weapon.description}<br>>", time)

    def new_char(self):
        """Outputs final stats, armour, and inventory"""
        typingPrint("We will now generate random stats for your character.<br>", time)
        self.introduce()
        print(' ')
        time.sleep(2)
        self.rollStats()
        self.set_stats()
        print(' ')
        self.getModifier()
        self.current_stats()
        print(' ')
        time.sleep(2)
        self.current_equip()
        print(' ')
        current_inventory()
        print(' ')

    def rollStats(self):
        """Rolls stats 4d6kh3"""
        # Roll stats
        typingPrint("Rolling for Strength...\n", time)
        self.dice_rolls("Strength")
        typingPrint(f'Strength: {self.stats["Strength"]}\n', time)
        time.sleep(1)
        typingPrint("Rolling for Dexterity...\n", time)
        self.dice_rolls("Dexterity")
        typingPrint(f'Dexterity: {self.stats["Dexterity"]}\n', time)
        time.sleep(1)
        typingPrint("Rolling for Constitution...\n", time)
        self.dice_rolls("Constitution")
        typingPrint(f'Constitution: {self.stats["Constitution"]}\n', time)
        time.sleep(1)
        typingPrint("Rolling for Intelligence...\n", time)
        self.dice_rolls("Intelligence")
        typingPrint(f'Intelligence: {self.stats["Intelligence"]}\n', time)
        time.sleep(1)
        typingPrint("Rolling for Wisdom...\n", time)
        self.dice_rolls("Wisdom")
        typingPrint(f'Wisdom: {self.stats["Wisdom"]}\n', time)
        time.sleep(1)
        typingPrint("Rolling for Charisma...\n", time)
        self.dice_rolls("Charisma")
        typingPrint(f'Charisma: {self.stats["Charisma"]}\n', time)
        time.sleep(1)

    def health_check(self):
        """Print out current/max HP"""
        print(f'You have {self.currentHP}/{self.maxHP} HP.')

    def take_damage(self, DMGtype, size):
        """Define the damage type and dice size"""
        damage = randint(1, size)
        if DMGtype in self.elemental_resistance or DMGtype in self.physical_resistance:
            damage //= 2
        self.currentHP -= damage
        return damage

    def dice_rolls(self, attribute):
        """Rolling 4d6 to get stats for PC"""
        rolls = []
        # roll 4d6
        for roll in range(4):
            r = randint(1, 6)
            rolls.append(r)
        # Drop the lowest number
        del rolls[rolls.index(min(rolls))]
        self.stats[attribute] += sum(rolls)
        return attribute


# Inventory list
def current_inventory():
    """Prints a list of items in your backpack that aren't equipped to your person."""
    typingPrint(f'In your rucksack you have:\n', time)
    for item_key, item_value in user.inventory.items():
        for key, value in item_value.items():
            if key == "equipped" and value == False:
                typingPrint(f'{item_key.name}\n'
                            f'    {item_key.description}\n', time)


def helpMenu():
    helpmenu = "This is the help menu"
    return helpmenu


# Equipment list
# def equipment():

# elif event.type == pygame_gui.UI_TEXT_ENTRY_FINISHED:
#     a = userTextEntry.get_text()
#     if a == "armor":
#         return (f"<br>You currently have equipped:<br> {user.armor}<br>"
#                 f"Would you like to equip something new? Y/N")
#
#     elif a == "weapons":
#         return (f"<br>You currently have equipped:<br> {user.weapon}<br>"
#                 f"Would you like to equip something new? Y/N")


def equipped():
    """Print currently equipped, print a list of held armor pieces,
    if input matches a held item, replace equipped condition"""

    text = f"You currently have equipped: {user.armor}\n Would you like to equip something new? Y/N"
    if event.type == pygame_gui.UI_BUTTON_PRESSED:
        if event.ui_element == helpButton:
            for item_key, item_value in user.inventory.items():
                # item_info = dict
                for key, value in item_value.items():
                    # Leather armor[items], "object"[key], Armor[value]
                    if key == "object" and value == Armor:
                        armor_list = "\n", item_key
                        return armor_list
    else:
        else_comment = "I'm sorry, I didn't understand that.\nWould you like to equip something new? Y/N"
        return else_comment
    return text


class DamageType(Enum):
    SLASHING = auto()
    CRUSHING = auto()
    PIERCING = auto()
    FIRE = auto()
    WATER = auto()
    LIGHTNING = auto()


class DamageMod(Enum):
    STRENGTH = auto()
    DEXTERITY = auto()
    CONSTITUTION = auto()
    INTELLIGENCE = auto()
    WISDOM = auto()
    CHARISMA = auto()


class Item:
    """The base class for all items"""

    def __init__(self, name, description, value, magical):
        self.name = name
        self.description = description
        self.value = value
        self.magical = magical

    def __repr__(self):
        return f"{self.name}<br>=====<br>{self.description}<br>Value: {self.value}<br>"


class Money(Item):
    """The currency item used in the world of Kanjin"""

    def __init__(self, name, amt, magical):
        self.name = name
        self.amt = amt
        self.magical = magical
        super().__init__(name=self.name,
                         description=f"A small round coin made of {self.name.lower()} "
                                     f"with the imperial city logo stamped on the face.",
                         value=self.amt,
                         magical=self.magical)


class Weapon(Item):
    """The base class for all weapons"""

    def __init__(self, name, description, value, damage1H, damage2H, dmgType, dmgMod, vers, thrown, magical):
        self.damage1H = damage1H
        self.damage2H = damage2H
        self.dmgType = dmgType
        self.dmgMod = dmgMod
        self.vers = vers
        self.thrown = thrown
        super().__init__(name, description, value, magical)

    def __repr__(self):
        return f"{self.name}<br>=====<br>{self.description}<br>Value: {self.value}" \
               f"<br>Damage: One Handed - {self.damage1H}" \
               f"<br>Damage: Two Handed - {self.damage2H}<br>" \
               f"Damage Type: {self.dmgType}<br>Magical: {self.magical}.<br>"


class Armor(Item):
    """The base class for all armor"""

    def __init__(self, name, description, value, grade, ac, disadvantage, dmgRes, magical):
        self.grade = grade
        self.ac = ac
        self.stealthDis = disadvantage
        self.dmgRes = dmgRes
        super().__init__(name, description, value, magical)

    def __repr__(self):
        if self.stealthDis:
            return f"{self.name}<br>=====<br>{self.description}<br>Value: {self.value}<br>" \
                   f"AC: {self.ac}<br>Magical: {self.magical}"
        elif not self.stealthDis:
            return f"{self.name}<br>=====<br>{self.description}<br>Value: {self.value}<br>" \
                   f"AC: {self.ac}<br>Disadvantage on Stealth checks: {self.stealthDis}<br>Magical: {self.magical}"


# Different types of coins
GP1 = Money("Gold", 1, False)
SP1 = Money("Silver", 1, False)
CP1 = Money("Copper", 1, False)

rock = Weapon(
    name="Rock",
    description="A fist-sized rock, suitable for bludgeoning.",
    value="No value",
    damage1H=randint(1, 6),
    damage2H=0,
    dmgType=DamageType.CRUSHING,
    dmgMod=DamageMod.STRENGTH,
    vers=False,
    thrown=True,
    magical=False
)
tornRags = Armor(
    name="Torn Rags",
    description="A ripped and worn-out outfit.",
    value=0,
    grade="Light",
    ac=0,
    disadvantage=True,
    dmgRes="None",
    magical=False
)

user = Player("Jamie", "Male", 29, "Elf", "Mage")
pygame.init()

# Create a screen
screen = pygame.display.set_mode((1240, 720))
screen.fill("black")

# Set title and Icon
pygame.display.set_caption('Kanjin: An RPG Text Adventure')
icon = pygame.image.load("icon.png").convert_alpha()
pygame.display.set_icon(icon)

# ((size), "theme.json")
manager = pygame_gui.UIManager((1200, 720))
manager.set_visual_debug_mode(False)

# Set surface elements
# relative_rect = pygame.Rect((top left position)(UIButton size))
userInputButton = pygame_gui.elements.UIButton(relative_rect=pygame.Rect((708, 642), (115, 33)),
                                               text='Send',
                                               manager=manager,
                                               object_id="#userInputButton")

inventoryButton = pygame_gui.elements.UIButton(relative_rect=pygame.Rect((1085, 20), (107, 100)),
                                               text='Inventory',
                                               manager=manager,
                                               object_id="#inventoryButton")

equipmentButton = pygame_gui.elements.UIButton(relative_rect=pygame.Rect((1085, 150), (107, 100)),
                                               text='Equipment',
                                               manager=manager,
                                               object_id="#equipmentButton")

helpButton = pygame_gui.elements.UIButton(relative_rect=pygame.Rect((1085, 280), (107, 100)),
                                          text='Help',
                                          manager=manager,
                                          object_id="#helpButton")

sceneImage_surface = pygame.Surface((1003, 242))
sceneImage_surface.fill((34, 40, 45))
sceneImage_image = pygame_gui.elements.UIImage(relative_rect=pygame.Rect((20, 20), (1003, 242)),
                                               image_surface=icon,
                                               manager=manager,
                                               object_id="#sceneImage")

userTextEntry_surface = pygame.Surface((645, 33))
userTextEntry = pygame_gui.elements.UITextEntryLine(pygame.Rect((20, 642), (645, 33)),
                                                    manager=manager,
                                                    object_id="#player_input")
sceneText_surface = pygame.Surface((1003, 325))
sceneText = pygame_gui.elements.UITextBox("Test",
                                          pygame.Rect((20, 282), (803, 325)),
                                          manager=manager,
                                          object_id="#scene_text")
# Typewriter Text
sceneText.set_active_effect(pygame_gui.TEXT_EFFECT_TYPING_APPEAR,
                            params={'time_per_letter': 0.001,
                                    'time_per_letter_deviation': 0.0003}

                            )

# Set FPS
clock = pygame.time.Clock()

# Engine loop
equipmentButtonPressed = False
while True:
    selection = "Not selected"
    time_delta = clock.tick(60) / 1000.0
    for event in pygame.event.get():

        if event.type == pygame.QUIT:
            quit()

        if event.type == pygame_gui.UI_BUTTON_PRESSED:
            if event.ui_element == userInputButton:
                sceneText.append_html_text("<br>" + userTextEntry.get_text())
                userTextEntry.set_text("")

        if event.type == pygame_gui.UI_TEXT_ENTRY_FINISHED:
            if not equipmentButtonPressed:
                if userTextEntry.get_text().lower() == "clear":
                    sceneText = pygame_gui.elements.UITextBox("",
                                                              pygame.Rect((20, 282), (803, 325)),
                                                              manager=manager,
                                                              object_id="#scene_text")
                    userTextEntry.set_text("")
                else:
                    selection = "text"
                    print("selection " + selection)
                    print(f"equip button pressed: {equipmentButtonPressed}")
                    sceneText.append_html_text("<br>" + userTextEntry.get_text())
                    userTextEntry.set_text("")

        if event.type == pygame_gui.UI_TEXT_ENTRY_FINISHED:
            if equipmentButtonPressed:
                if userTextEntry.get_text().lower() == "armor":
                    selection = "armor"
                    sceneText.append_html_text("<br><br>" + f"You currently have equipped:<br> "
                                                            f"<b>{user.armor}</b><br>"
                                                            f"Would you like to equip something new? Y/N")
                    userTextEntry.set_text("")
                    # equipmentButtonPressed = False

                elif userTextEntry.get_text().lower() == "weapons":
                    sceneText.append_html_text(f"<br>You currently have equipped:<br> {user.weapon}<br>"
                                               f"Would you like to equip something new? Y/N")
                    userTextEntry.set_text("")
                    equipmentButtonPressed = False

                else:
                    sceneText.append_html_text(f"<br>Sorry, I didn't understand that. Try again.")
                    userTextEntry.set_text("")

        if event.type == pygame_gui.UI_BUTTON_PRESSED:
            if event.ui_element == equipmentButton:
                print("pressed button")
                print(f"equip button pressed: {equipmentButtonPressed}")
                equipmentButtonPressed = True
                sceneText.append_html_text("<br>" + f"You currently have equipped: {user.armor}<br>"
                                                    f"Type 'armor' or 'weapons' to change equipment. ")
                print("code executed")
                print(f"equip button pressed: {equipmentButtonPressed}")

        manager.process_events(event)

    manager.update(time_delta)

    # Blit
    screen.blit(sceneText_surface, (20, 282))
    screen.blit(userTextEntry_surface, (20, 642))
    screen.blit(sceneImage_surface, (20, 20))

    manager.draw_ui(screen)
    pygame.display.update()
