# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
# SPDX-License-Identifier: GPL-3.0-or-later

import curses
from random import randint
from typing import List

from squirrelbattle.menus import Menu, MainMenu
from .display import Box, Display
from ..enums import KeyValues
from ..game import Game
from ..resources import ResourceManager
from ..translations import gettext as _


class MenuDisplay(Display):
    """
    A class to display the menu objects.
    """
    position: int

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.menubox = Box(*args, **kwargs)

    def update_menu(self, menu: Menu) -> None:
        self.menu = menu

        # Menu values are printed in pad
        self.pad = self.newpad(self.trueheight, self.truewidth + 2)

    def update_pad(self) -> None:
        for i in range(self.trueheight):
            self.addstr(self.pad, i, 0, "   " + self.values[i])
        # set a marker on the selected line
        self.addstr(self.pad, self.menu.position, 0, " >")

    def display(self) -> None:
        cornery = 0 if self.height - 2 >= self.menu.position - 1 \
            else self.trueheight - self.height + 2 \
            if self.height - 2 >= self.trueheight - self.menu.position else 0

        # Menu box
        self.menubox.refresh(self.y, self.x, self.height, self.width)
        self.pad.erase()
        self.update_pad()
        self.refresh_pad(self.pad, cornery, 0, self.y + 1, self.x + 1,
                         self.height - 2 + self.y,
                         self.width - 2 + self.x)

    def handle_click(self, y: int, x: int, game: Game) -> None:
        """
        We can select a menu item with the mouse.
        """
        self.menu.position = max(0, min(len(self.menu.values) - 1, y - 1))
        game.handle_key_pressed(KeyValues.ENTER)

    @property
    def truewidth(self) -> int:
        return max([len(str(a)) for a in self.values])

    @property
    def trueheight(self) -> int:
        return len(self.values)

    @property
    def preferred_width(self) -> int:
        return self.truewidth + 6

    @property
    def preferred_height(self) -> int:
        return self.trueheight + 2

    @property
    def values(self) -> List[str]:
        return [str(a) for a in self.menu.values]


class SettingsMenuDisplay(MenuDisplay):
    """
    A class to display specifically a settingsmenu object.
    """
    @property
    def values(self) -> List[str]:
        return [_(a[1][1]) + (" : "
                + ("?" if self.menu.waiting_for_key
                    and a == self.menu.validate() else a[1][0]
                   .replace("\n", "\\n"))
            if a[1][0] else "") for a in self.menu.values]


class MainMenuDisplay(Display):
    """
    A class to display specifically a mainmenu object.
    """
    def __init__(self, menu: MainMenu, *args):
        super().__init__(*args)
        self.menu = menu

        with open(ResourceManager.get_asset_path("ascii_art.txt"), "r") as file:
            self.title = file.read().split("\n")

        self.pad = self.newpad(max(self.rows, len(self.title) + 30),
                               max(len(self.title[0]) + 5, self.cols))

        self.fg_color = curses.COLOR_WHITE

        self.menudisplay = MenuDisplay(self.screen, self.pack)
        self.menudisplay.update_menu(self.menu)

    def display(self) -> None:
        for i in range(len(self.title)):
            self.addstr(self.pad, 4 + i, max(self.width // 2
                        - len(self.title[0]) // 2 - 1, 0), self.title[i],
                        self.fg_color)
        self.refresh_pad(self.pad, 0, 0, self.y, self.x,
                         self.height + self.y - 1,
                         self.width + self.x - 1)
        menuwidth = min(self.menudisplay.preferred_width, self.width)
        menuy, menux = len(self.title) + 8, self.width // 2 - menuwidth // 2 - 1
        self.menudisplay.refresh(
            menuy, menux, min(self.menudisplay.preferred_height,
                              self.height - menuy), menuwidth)

    def handle_click(self, y: int, x: int, game: Game) -> None:
        menuwidth = min(self.menudisplay.preferred_width, self.width)
        menuy, menux = len(self.title) + 8, self.width // 2 - menuwidth // 2 - 1
        menuheight = min(self.menudisplay.preferred_height, self.height - menuy)

        if menuy <= y < menuy + menuheight and menux <= x < menux + menuwidth:
            self.menudisplay.handle_click(y - menuy, x - menux, game)

        if y <= len(self.title):
            self.fg_color = randint(0, 1000), randint(0, 1000), randint(0, 1000)


class PlayerInventoryDisplay(MenuDisplay):
    """
    A class to handle the display of the player's inventory.
    """
    def update_pad(self) -> None:
        self.menubox.update_title(_("INVENTORY"))
        for i, item in enumerate(self.menu.values):
            rep = self.pack[item.name.upper()]
            selection = f"[{rep}]" if i == self.menu.position else f" {rep} "
            self.addstr(self.pad, i + 1, 0, selection
                        + " " + item.translated_name.capitalize())

    @property
    def truewidth(self) -> int:
        return max(1, self.height if hasattr(self, "height") else 10)

    @property
    def trueheight(self) -> int:
        return 2 + super().trueheight

    def handle_click(self, y: int, x: int, game: Game) -> None:
        """
        We can select a menu item with the mouse.
        """
        self.menu.position = max(0, min(len(self.menu.values) - 1, y - 2))
        game.handle_key_pressed(KeyValues.ENTER)


class StoreInventoryDisplay(MenuDisplay):
    """
    A class to handle the display of a merchant's inventory.
    """
    def update_pad(self) -> None:
        self.menubox.update_title(_("STALL"))
        for i, item in enumerate(self.menu.values):
            rep = self.pack[item.name.upper()]
            selection = f"[{rep}]" if i == self.menu.position else f" {rep} "
            self.addstr(self.pad, i + 1, 0, selection
                        + " " + item.translated_name.capitalize()
                        + ": " + str(item.price) + " Hazels")

    @property
    def truewidth(self) -> int:
        return max(1, self.height if hasattr(self, "height") else 10)

    @property
    def trueheight(self) -> int:
        return 2 + super().trueheight

    def handle_click(self, y: int, x: int, game: Game) -> None:
        """
        We can select a menu item with the mouse.
        """
        self.menu.position = max(0, min(len(self.menu.values) - 1, y - 2))
        game.handle_key_pressed(KeyValues.ENTER)