import urwid
import logging

from .constants import VISIBILITY_OPTIONS
from .widgets import Button, EditBox

logger = logging.getLogger(__name__)


class StatusComposer(urwid.Frame):
    """
    UI for composing or editing a status message.

    To edit a status, provide the original status in 'edit', and optionally
    provide the status source (from the /status/:id/source API endpoint) in
    'source'; this should have at least a 'text' member, and optionally
    'spoiler_text'.  If source is not provided, the formatted HTML will be
    presented to the user for editing.
    """
    signals = ["close", "post"]

    def __init__(self, max_chars, username, visibility, in_reply_to=None,
                 edit=None, source=None):
        self.in_reply_to = in_reply_to
        self.max_chars = max_chars
        self.username = username
        self.edit = edit

        self.cw_edit = None
        self.cw_add_button = Button("Add content warning",
            on_press=self.add_content_warning)
        self.cw_remove_button = Button("Remove content warning",
            on_press=self.remove_content_warning)

        if edit:
            if source is None:
                text = edit.data["content"]
            else:
                text = source.get("text", edit.data["content"])

                if 'spoiler_text' in source:
                    self.cw_edit = EditBox(multiline=True, allow_tab=True,
                                           edit_text=source['spoiler_text'])

            self.visibility = edit.data["visibility"]

        else:   # not edit
            text = self.get_initial_text(in_reply_to)
            self.visibility = (
                in_reply_to.visibility if in_reply_to else visibility
            )

        self.content_edit = EditBox(
            edit_text=text, edit_pos=len(text), multiline=True, allow_tab=True)
        urwid.connect_signal(self.content_edit.edit, "change", self.text_changed)

        self.char_count = urwid.Text(["0/{}".format(max_chars)])

        self.visibility_button = Button("Visibility: {}".format(self.visibility),
            on_press=self.choose_visibility)

        self.post_button = Button("Edit" if edit else "Post", on_press=self.post)
        self.cancel_button = Button("Cancel", on_press=self.close)

        contents = list(self.generate_list_items())
        self.walker = urwid.SimpleListWalker(contents)
        self.listbox = urwid.ListBox(self.walker)
        return super().__init__(self.listbox)

    def get_initial_text(self, in_reply_to):
        if not in_reply_to:
            return ""

        text = '' if in_reply_to.is_mine else '@{} '.format(in_reply_to.original.account)
        mentions = ['@{}'.format(m["acct"]) for m in in_reply_to.mentions if m["acct"] != self.username]
        if mentions:
            text += '\n\n{}'.format(' '.join(mentions))

        return text

    def text_changed(self, edit, text):
        count = self.max_chars - len(text)
        text = "{}/{}".format(count, self.max_chars)
        color = "warning" if count < 0 else ""
        self.char_count.set_text((color, text))

    def generate_list_items(self):
        if self.in_reply_to:
            yield urwid.Text(("dim", "Replying to {}".format(self.in_reply_to.original.account)))
            yield urwid.AttrWrap(urwid.Divider("-"), "dim")

        yield urwid.Text("Status message")
        yield self.content_edit
        yield self.char_count
        yield urwid.Divider()

        if self.cw_edit:
            yield urwid.Text("Content warning")
            yield self.cw_edit
            yield urwid.Divider()
            yield self.cw_remove_button
        else:
            yield self.cw_add_button

        yield self.visibility_button
        yield self.post_button
        yield self.cancel_button

    def refresh(self):
        self.walker = urwid.SimpleListWalker(list(self.generate_list_items()))
        self.listbox.body = self.walker

    def choose_visibility(self, *args):
        list_items = [urwid.Text("Choose status visibility:")]
        for visibility, caption, description in VISIBILITY_OPTIONS:
            text = "{} - {}".format(caption, description)
            button = Button(text, on_press=self.set_visibility, user_data=visibility)
            list_items.append(button)

        self.walker = urwid.SimpleListWalker(list_items)
        self.listbox.body = self.walker

        # Initially focus currently chosen visibility
        focus_map = {v[0]: n + 1 for n, v in enumerate(VISIBILITY_OPTIONS)}
        focus = focus_map.get(self.visibility, 1)
        self.walker.set_focus(focus)

    def set_visibility(self, widget, visibility):
        self.visibility = visibility
        self.visibility_button.set_label("Visibility: {}".format(self.visibility))
        self.refresh()
        self.walker.set_focus(7 if self.cw_edit else 4)

    def add_content_warning(self, button):
        self.cw_edit = EditBox(multiline=True, allow_tab=True)
        self.refresh()
        self.walker.set_focus(4)

    def remove_content_warning(self, button):
        self.cw_edit = None
        self.refresh()
        self.walker.set_focus(3)

    def set_error_message(self, msg):
        self.footer = urwid.Text(("footer_message_error", msg))

    def clear_error_message(self):
        self.footer = None

    def post(self, button):
        self.clear_error_message()

        # Don't lstrip content to avoid removing intentional leading whitespace
        # However, do strip both sides to check if there is any content there
        content = self.content_edit.edit_text.rstrip()
        content = None if not content.strip() else content

        warning = self.cw_edit.edit_text.rstrip() if self.cw_edit else ""
        warning = None if not warning.strip() else warning

        if not content:
            self.set_error_message("Cannot post an empty message")
            return

        in_reply_to_id = self.in_reply_to.id if self.in_reply_to else None
        self._emit("post", content, warning, self.visibility, in_reply_to_id)

    def close(self, button):
        self._emit("close")
