"""
This plugin allows sending message retractions on our own messages.

Command
-------

.. glossary::

    /retract
        **Usage:** ``/retract <message time>``
"""

from poezio.decorators import command_args_parser
from poezio.plugin import BasePlugin
from poezio.core.structs import Completion
from poezio.windows.inputs import Input
from poezio.ui.types import Message
from poezio import tabs


DATETIME_FORMAT = '%Y-%m-%dT%H:%M:%S'


class Plugin(BasePlugin):
    """Message Retraction (XEP-0424) plugin"""

    def init(self) -> None:
        self.core.xmpp.register_plugin('xep_0424')

        for _tabtype in (tabs.MucTab, tabs.DynamicConversationTab,
                         tabs.StaticConversationTab, tabs.PrivateTab):
            self.api.add_tab_command(
                _tabtype,
                name='retract',
                handler=self.command_retract,
                usage='<message time>',
                help='Retract one of your messages using its timestamp (using tab complete)',
                short='Retract a message using its timestamp',
                completion=self.completion_retract,
            )

    def completion_retract(self, the_input: Input) -> Completion | None:
        """Datetime completion"""
        if the_input.get_argument_position() != 1:
            return None
        tab = self.api.current_tab()
        if not isinstance(tab, tabs.ChatTab):
            return None

        all_messages = self.api.get_conversation_messages()[:-100:-1]
        # We want our own messages only
        if isinstance(tab, tabs.MucTab):
            filtered_messages = [
                m for m in all_messages
                if isinstance(m, Message) and m.user and m.user == tab.own_user
            ]
        else:
            filtered_messages = [
                m for m in all_messages
                if isinstance(m, Message) and m.jid and m.jid.bare == self.core.xmpp.boundjid.bare
            ]
        messages = list(map(lambda m: m.time.strftime(DATETIME_FORMAT), filtered_messages))

        if not messages:
            return None

        return Completion(the_input.auto_completion, messages, quotify=False)

    @command_args_parser.raw
    async def command_retract(self, args: str) -> None:
        """Moderate a message in a chatroom"""
        if not args:
            return
        time = args.strip()

        tab = self.api.current_tab()
        if not isinstance(tab, tabs.ChatTab):
            return
        is_muc = isinstance(tab, tabs.MucTab)

        found_msg = self.api.find_message(time, DATETIME_FORMAT)
        # TODO: do better here
        # cannot re-use is_muc because mypy is not smart enough
        if isinstance(tab, tabs.MucTab) and found_msg and found_msg.user != tab.own_user:
            self.api.information(
                'Unable to retract message: duplicate timestamps',
                'Error',
            )
        if not found_msg:
            self.api.information(
                f'Message with timestamp “{time}” not found.',
                'Error',
            )
            return

        mtype = 'chat'
        id_ = found_msg.identifier
        if is_muc:
            id_ = found_msg.stanza_id or ''
            mtype = 'groupchat'
            if not id_:
                self.api.information(
                    f'Message with timestamp “{time}” '
                    'found but contained no “{urn:xmpp:sid:0}stanza-id” identifier.',
                    'Error',
                )
                return

        jid = tab.jid
        self.core.xmpp['xep_0424'].send_retraction(jid, id_, mtype=mtype)
        if isinstance(tab, tabs.OneToOneTab) and found_msg.jid:
            tab.handle_retract_values(id_, found_msg.jid)
