#!/usr/bin/env python

from re import sub
from string import punctuation

from evennia.commands.default.muxcommand import MuxCommand
from evennia import CmdSet
from evennia.utils import logger
from evennia.utils.eveditor import EvEditor

from commands.command import Command


class CmdKnock(Command):
    """
    The ability to knock on something, like a door.

    Usage:

      knock

    Uh, yeah, you'll need to make sure the ring is in the mouth of the
    door knocker.
    """
    key = "knock"

    def func(self):
        logger.log_info(f"Seems like {self.caller.key} wants to knock on me.")
        self.obj.do_knock(self.caller)


class CmdSetKnock(CmdSet):
    def at_cmdset_creation(self):
        self.add(CmdKnock)


class CmdJump(Command):
    """
    Jump or play in or around puddles.

    Usage:

      jump

    You know you want to do this!
    """
    key = "jump"
    aliases = ["play"]

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


class CmdSetPuddle(CmdSet):
    def at_cmdset_creation(self):
        self.add(CmdJump)


class CmdThrow(Command):
    """
    Throw a stick or a fish back into the water.

    Usage:

      throw [ object ]
    """
    key = "throw"
    locks = "holds(stick)"

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


class CmdSetStick(CmdSet):
    def at_cmdset_creation(self):
        self.add(CmdThrow)


class CmdLight(Command):
    """
    Light something on fire.

    Usage:

      light <object>

    Want to relax into the old stories, light a pipe.
    Want to see in a dungeon, use this to light a
    torch or a candle, if you have such an item.
    """
    key = "light"

    def func(self):
        lighter = self.caller
        item = self.args.strip()
        if item == "":
            lighter.msg("What do you want to light?")
            return

        burnables = lighter.search(item, location=lighter, quiet=True)
        if burnables and len(burnables) > 0:
            to_burn = burnables[0]
            if to_burn.has_method("do_light"):
                to_burn.do_light(self.caller)
            else:
                lighter.msg(f"The {burnables[0].key} isn't flammable.")
        else:
            lighter.msg(f"Can't find {item}.")



class CmdSmoke(MuxCommand):
    """
    Smoke and blow a shape with your magical pipe.

    Usage:

      smoke [ option [= description]]

    Where 'options' can be:

      - ring : a traditional or multicolored smoke ring
      - monster : a monstrous shape, where 'description'
               is the name of the shape.
      - arrow : where 'description' is where the smoke
               points to.

    If an 'option' is not given, then resorts to the attribute,
    'smoke_msg'.
    """
    key = "smoke"
    aliases = ['puff']
    locks = "cmd:holds()"

    def func(self):
        if self.lhs:
            if self.lhs == 'ring':
                self.obj.do_ring(self.caller, self.rhs)
            elif self.lhs == 'arrow':
                self.obj.do_arrow(self.caller, self.rhs)
            elif self.lhs == 'monster':
                self.obj.do_monster(self.caller, self.rhs)
            else:
                self.caller.msg(f"The option, '{self.lhs}' isn't available.")
        else:
            self.obj.do_smoke(self.caller)


class CmdSetSmoke(CmdSet):
    def at_cmdset_creation(self):
        self.add(CmdSmoke)



class CmdWrite(MuxCommand):
    """Write something down.

    Usage:

      write

    This brings up a strange little editor, where you can type the
    message, and edit the individual lines.

    """
    key = "write"

    def func(self):
        EvEditor(self.caller,
                 loadfunc=self.obj.do_write_begin,
                 savefunc=self.obj.do_write,
                 quitfunc=self.obj.do_write_end,
                 key="Type ':q' on its own line when done.")


class CmdSetWrite(CmdSet):
    def at_cmdset_creation(self):
        self.add(CmdWrite)


class CmdRummage(MuxCommand):
    """
    Rummage around in an object that contains stuff.

    Usage:

      rummage
    """
    key = "rummage"
    locks = "cmd:holds()"

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


class CmdKeep(MuxCommand):
    """
    Move the item found into your inventory.
    You can then |ggive|n that item to others.

    Usage:

      keep [ description ]

    The optional |wdescription|n is shown if you |glook|n
    at the object.
    """
    key = "keep"
    locks = "cmd:holds()"

    def func(self):
        self.obj.do_keep(self.caller, self.args.strip())


class CmdSetRummage(CmdSet):
    def at_cmdset_creation(self):
        self.add(CmdRummage)
        self.add(CmdKeep)


class CmdCat(Command):
    """Have your cat do some antic.

    Usage:

      cat <phrase>

    Or:

      cat's <phrase>

    Will announce your cat's antics to the room.

    You can target another character by preceding the character's
    description with a |w/|n, as in |w/elf|n or |w/blonde elf|n.
    """
    key = "cat"

    def func(self):
        self.obj.at_do(self.caller, self.args.strip())


class CmdSetCat(CmdSet):
    def at_cmdset_creation(self):
        self.add(CmdCat)


class CmdOctopus(Command):
    """
    Have your octopus do some antics.

    Usage:

      octopus <phrase>

    Or:

      octopus's <phrase>

    Will announce your octopus's antics to the room.

    You can target another character in the antics by preceding the
    character's description with a |w/|n, as in |w/elf|n
    or |w/blonde elf|n.
    """
    key = "octopus"
    aliases = ["pus"]

    def func(self):
        self.obj.at_do(self.caller, self.args.strip())


class CmdSetOctopus(CmdSet):
    def at_cmdset_creation(self):
        self.add(CmdOctopus)


class CmdFrog(Command):
    """
    Have your frog do some antics.

    Usage:

      frog <phrase>

    Or:

      frog's <phrase>

    Will announce your frog's antics to the room.

    You can target another character in the antics by preceding the
    character's description with a |w/|n, as in |w/elf|n
    or |w/blonde elf|n.
    """
    key = "frog"
    aliases = ["frogs", "toad", "toads"]

    def func(self):
        self.obj.at_do(self.caller, self.args.strip(), self.cmdstring)


class CmdSetFrog(CmdSet):
    def at_cmdset_creation(self):
        self.add(CmdFrog)


class CmdAntic(Command):
    """Have your familiar do some antic.

    Usage:

      antic <phrase>

    Or:

      antic's <phrase>

    Will announce your familiar's antics to the room.

    You can target another character by preceding the character's
    description with a |w/|n, as in |w/elf|n or |w/blonde elf|n.
    """
    key = "antic"
    aliases = ["beastie"]

    def func(self):
        self.obj.at_do(self.caller, self.args.strip())


class CmdSetAntic(CmdSet):
    def at_cmdset_creation(self):
        self.add(CmdAntic)


class CmdRoll(MuxCommand):
    """
    Roll the dice in your inventory.

    Usage:

      roll

    Or:

      roll/switches

    Will announce your roll to the room. If you have more than one
    dice, the following switches are available:

      sum : Report the sum of the dice
      high : Report only the highest (advantage)
      low : Report only the lowest (disadvantage)

    """
    key = "roll"
    locks = "cmd:holds()"
    switch_options = ("sum", "high", "low")

    def func(self):
        self.obj.roll(self.caller, self.switches)


class CmdSetDice(CmdSet):
    def at_cmdset_creation(self):
        self.add(CmdRoll)


class CmdPress(Command):
    """
    Press buttons or something similar.

    Usage:

      press

    Or:

      press [ details ]

    """
    key = "press"
    alias = ["touch"]

    def func(self):
        details = sub(rf"[{punctuation} \t]*", "", self.args)
        self.obj.trigger(self.caller, details)


class CmdSetPress(CmdSet):
    def at_cmdset_creation(self):
        self.add(CmdPress)


class CmdTransform(MuxCommand):
    """Transform yourself into an object.

    Usage:

      |gtransform <object> = <description>|n

    Where the 'object' is what you might see when looking around a
    room, and 'description' is what is shown when a character 'look's
    at you.

    See |guntransform|n.
    """
    key = "transform"
    alias = ["transmogrify"]

    def func(self):
        if self.caller.attributes.get('transformed'):
            self.caller.msg(f"You have already transformed into a {self.caller.name}."
                            f" You need to |guntransform|n first.")
        elif not self.lhs:
            self.caller.msg("What do you want to transform into?")
        elif not self.rhs:
            self.caller.msg(f"You need to describe this '{self.lhs}'.")
        else:
            self.caller.transmogrify(self.lhs, self.rhs)


class CmdUntransform(Command):
    """
    Untransform yourself from a previous 'transform' command.

    Usage:

      |guntransform|n
    """
    key = "untransform"
    alias = ["untransmogrify"]

    def func(self):
        if self.caller.attributes.get('transformed'):
            self.caller.untransmogrify()
        else:
            self.caller.msg("You are not an object.")


class CmdSetTransform(CmdSet):
    """
    Transforming set.
    """
    def at_cmdset_creation(self):
        self.add(CmdTransform)
        self.add(CmdUntransform)


class CmdPeer(Command):
    """
    Closely examine an object past the magic and see if they are a
    transformed character, or really the object.

    Usage:

      |gpeer <object>|n

    """
    key = "peer"
    alias = ["seek"]

    def func(self):
        looker = self.caller
        label = self.args.strip()

        if label == "":
            looker.msg("What do you want to closely examine?")
            return

        thing = looker.search(label)
        if thing:
            if thing.attributes.get("transformed"):
                self.obj.found_someone(thing)
                looker.msg(f"Aha! The {label} is not how it appears!|/" +
                           f"It is really a |c{thing.db.orig_sdesc}|n... " +
                           thing.db.orig_desc)
                thing.msg(f"The {looker.get_display_name(thing)} peers closely at you.|/" +
                          f"The jig is up! {looker.pronoun_subjective()} knows " +
                          f"that you are not a {label}.")
            else:
                self.obj.failed_at_looking()
                looker.msg(f"The {label} is what it is...|/" + thing.db.desc)


class CmdSetPeer(CmdSet):
    """
    Peering set.
    """
    def at_cmdset_creation(self):
        self.add(CmdPeer)
