#!/usr/bin/env python

from enum import Enum
from random import choice

from evennia import (
    Command,
    CmdSet,
    TICKER_HANDLER,
)
from evennia.utils import delay
from evennia.prototypes.spawner import spawn

from typeclasses.npcs import CarriableNPC
from utils.word_list import routput


MSGS = {
    "START": [
        "A small bird flies over to you, and perches on your shoulder. It definitely has a top hat. \"Hello,\" it says in your ear. \"I'm Bubba Joe Washington, the Third, and I'm here to help you figure out this game by breaking the fourth wall. Feel free to |gshoo|n me away, and I'll leave you alone to explore.\"",
        "The bird with yellow cheeks says, \"In this story game, you type commands (verbs) to do things. For instance, type the word |glook|n, and press the |wReturn|n key to look around at your surroundings and to see where you are, what you can do, and where you can go.\"",
        "\"That's right,\" it chirps, \"Any words in this game, shown in |gthis color|n are commands that you can type.\""
        "The bird perched on your shoulder looks at you expectantly.",
        "\"Go ahead,\" says the bird, \"Type |glook|n. If you are on the web site, you may need to click in the box in the lower part of the screen.\"",
        "The bird preens itself.",
        "The bird says, \"Would you like me to stay and help you out?\"",
        "\"If so,\" says the bird, \"type |glook|n to look around at your surroundings.\"",
    ],
    "LOOK": [
        "\"That's great,\" says the little cockatiel. \"From that, you know you are standing in a grove of trees near a puddle. You can now type |glook puddle|n to examine it.\"",
        "\"You can also |glook trees|n, |glook moss|n, or … well, you get the idea,\" it says.",
    ],
    "LOOKAT": [
        '"You seem to be getting the hang of this game," chirps the bird. "The game highlights some words, like |Yboulder|n, in yellow. This hints that you should look more closely at them. Also, you can |winteract|n with objects following the line: "You notice"',
        "The bird continues, \"When you typed |glook|n before, you noticed exits. These are directions or places you can go. For instance, if you type |geast|n (or just |ge|n as a shortcut), we can follow a path to a meadow where you might encounter the BHB, the Big Hairy Beast.\"",
        "\"It's adorable,\" the little bird on your shoulder says, \"So type |geast|n to follow the path there.\"",
        # "\"It's adorable,\" the little bird on your shoulder says. \"The path to the |gwest|n leads to Dabbler's place, and to the |gsouth|n, you can check out the sea where you can catch obnoxious fish.\"",
        "\"Yes, I could fly myself,\" warbles the little bird, \"but I'm trying to help you get around.\"",
        "The bird looks at you expectantly.",
        "\"Shall we explore other places?\" asks the bird on your shoulder.",
        "\"I hope I'm not rushing you,\" the bird mentions, \"as you can always come back to explore more.\"",
    ],
    "MOVE": [
        "\"Thanks for lift. This is a nice place,\" says the bird on your shoulder. \"When you come to a new area, the game shows you what you are seeing, so you don't have to type |glook|n … even though you still can.\"",
        "\"Another interesting command,\" it chirps, \"is the |gsay|n command, that lets you talk to anyone in the area. Usually, we use this command for talking to other players in the game, but some creatures also listen to what you say.\"",
        "\"Go ahead, just typing |gsay Hello.|n\"",
        '"When you say something," the bird says, "anyone nearby can here it, not just me.'
    ],
    "SAY": [
        "\"How's it going?\" the bird asks, \"Are you enjoying this game so far?\"",
        "\"A shortcut to |gsay|n is to type either a double or single quote, and then your message.\"",
        "\"If an area has more than one player or NPC,\" chirps the bird, \"you will want to direct your message. Try: |gsay to bird You're pretty.|n\"",
        "\"You can also use |gemote|n to state something about yourself, \" it says. \" For instance, type: |gemote smiles.|n\"",
        "The bird stands on one leg.",
        "Another useful command is |gpub|n which is a shortcut to sending messages to a public channel that everyone in the game receives |wout of character|n. That is, the message comes from your login account, not your character. The dad jokes go there without interrupting the role playing.",
        "The bird says, \"Typing |ghelp|n gives you a list of commands. That list changes depending on where you are and what you are carrying. For instance, you could type |gshoo|n for me to fly away, and then that command wouldn't be available again.\"",
        "The bird chirps, \"You can learn more about the individual commands. For instance, type |ghelp emote|n and you can see more options to that command. You can also see new commands, like |ghelp get|n.\"",
        "\"If you get stuck solving a puzzle,\" it says, \"Type |ghint|n, but type |ghelp hint|n to learn about it first.\""
        "\"Type |ghelp start|n for a repeat of much of what we've talked about,\" says the bird.",
        "The bird says, \"Hrm. What else? The |ginv|n shows you what you are carrying. I see you picked up a letter. You can also type |gread letter|n.\"",
        "\"Since this game hosts many users,\" says the bird, \"you can show them what they see when they look at you, using the |gsetdesc|n command. Check out the help on it as well as |gsdesc|n and |gpose|n.",
        "\"I'm guessing your last question,\" chirps the little bird on your shoulder, \"is what you should |wdo|n in this game.\"",
        "\"That is a good question,\" quips the bird. \"You |wcould|n look at this as a philosophical antidote for our existential apprehension of a post-modern world in the death throes of capitalism, but…\"",
        "The bird says, \"This is a cozy little game about role playing a storybook character in an alternate plane populated by the Faerie, so wander and look around. Find a cozy place to role play with others,\" says the bird.",
        "The little bird gives a wry grin, \"Type |gscore|n to give you a list of goals, and how many you've accomplished.\""
        "\"For instance, if you can find the secret alchemy lab,\" it says, \"you can craft potions, and if you find the |wmist horn|n, you can cross the sea for more adventures.\""
        "\"What do you say?\" says the bird. \"Think you got the hang of playing this?\"",
    ]
}

MSGS_WAITING = [
    "The <<little ^ gray ^ >> << bird ^ cockatiel >> <<on your shoulder ^ >> preens itself.",
    "The <<little ^ gray ^ >> << bird ^ cockatiel >> <<on your shoulder ^ >> <<looks ^ stares>> at you <<expectantly ^ waiting ^ patiently>>.",
    "The << bird ^ cockatiel >> looks up at the sky. \"It rains here often,\" it says.",
    "The << bird ^ cockatiel >> looks up at the sky. \"Looks like rain is coming,\" it says.",
    "\"I like the rain,\" the << bird ^ cockatiel >> says, \"as it keeps the moss green and the puddles full.\"",
    "\"They say if you don't like the weather,\" tweets the bird, \"just wait.\"",
]


class TutorialState(Enum):
    "The acceptable states of fishing."
    START = 0
    LOOK = 1
    LOOKAT = 2
    MOVE = 4
    SAY = 8


class CmdTutorial(Command):
    """
    Start (or restart) the tutorial.

    Usage:

       |gtutorial|n

    The |wtutorial bird|n, Bubba Joe Washington III, will re-join
    you to show you the ropes of this game. Type:

       |gshoo|n

    To stop the tutorial.
    """
    key = "tutorial"

    def func(self):
        TutorBird.do_start_tutorial(self.caller)


class CmdShoo(Command):
    """
    End the tutorial by shooing the bird away.

    Usage:

      |gshoo|n

    Restart the tutorial, and bring back Bubba, using the command:

      |gtutorial|n
    """
    key = "shoo"
    locks = "holds()"

    def func(self):
        self.obj.do_end_tutorial(self.caller)


class CmdSetBird(CmdSet):
    def at_cmdset_creation(self):
        self.add(CmdShoo)


class TutorBird(CarriableNPC):
    """
    Bird that routinely tells a player a new hint.
    """
    # The number of ticks (seconds) to check for the time for a message:
    bird_tick = 15

    # The number of waiting messages to issue before stopping the tutorial:
    wait_messages = 3

    def at_object_creation(self):
        self.cmdset.add_default(CmdSetBird)

        # Set the positions for all the different states:
        self.db.tutor_msg_num = {
            "START": 0,
            "LOOK": 0,
            "LOOKAT": 0,
            "MOVE": 0,
            "SAY": 0,
        }
        self.db.waiting = 0
        self.db.tutor_level = TutorialState.START

        TICKER_HANDLER.add(interval=self.bird_tick,
                           callback=self.do_speak)

    def do_start_tutorial(character):
        """
        Spawn the bird and attach it to character.
        """
        bird = spawn({
            "typeclass": "typeclasses.tutorial.TutorBird",
            "key": "bird",
            "aliases": ["cockatiel", "tutor", "tutor bird"],
            "desc": "Gray feathered bird with a top hat perched on your shoulder. It's large black eyes looks at you quizically. Its yellow cheeks are adorable, making it seem overly helpful.",
        })[0]
        bird.location = character
        delay(1, bird.display_first_image)
        delay(30, bird.display_second_image)

    def display_first_image(self):
        """
        Displays an image for the tutorial for the webclient.
        """
        self.location.msg(image=("https://www.howardabrams.com/cozy-players-guide/bubba-flying.jpg"))

    def display_second_image(self):
        """
        Displays an image for the tutorial for the webclient.
        """
        if self.location:
            self.location.msg(image=("https://www.howardabrams.com/cozy-players-guide/bubba.jpg"))

    def do_speak(self):
        """
        Called at a repeatable sequence by the ticker, and
        it calls at_say() in order to do a type of monologue.
        """
        character = self.location
        msg = self.get_msg(character)
        if msg:
            character.msg(f"\n{msg}")

    def get_msg(self, character):
        """
        Return a message based on the character's progression.
        The progression is marked by the character's variable:
        'tutorstate' (stored in its database).
        """
        # We could skip ahead if the player enters a higher state, so
        # we find the "max" state available:
        level = TutorialState(max([character.db.tutorstate & state.value
                                   for state in TutorialState]))
        choices = MSGS[level.name]
        msg_num = self.db.tutor_msg_num.get(level.name, 0)
        if msg_num >= len(choices):
            # Ran out of messages?
            if self.db.waiting > self.wait_messages or level == TutorialState.SAY:
                msg = self.do_end_tutorial(character)
            else:
                msg = routput(choice(MSGS_WAITING))
                self.db.waiting += 1
        else:
            msg = choices[msg_num]
            self.db.tutor_msg_num[level.name] += 1
            self.db.waiting = 0  # Reset the waiting period
        return msg

    def do_end_tutorial(self, character):
        """
        A visual way to stop the tutorial
        """
        character.msg("\"Have fun, and I'll leave you here,\" chirps the bird. \"Remember to check out the letter you picked up!\" It flies away.")
        self.delete()
