# -*- coding: utf-8 -*-
import os
from logging import getLogger
from typing import Optional

import requests
import wx

from mysc.image_utils import load_scaled_image
from wxUI import commonMessageDialogs

log = getLogger("wxUI.dialogs.mastodon.updateProfile")

#: Formats accepted when the user picks a new header or avatar.
IMAGE_WILDCARD = "Images (*.png;*.jpg;*.jpeg;*.gif;*.webp)|*.png;*.jpg;*.jpeg;*.gif;*.webp"


def return_true():
    return True


def download_scaled_image(url: str, width: int, height: int) -> Optional[wx.Image]:
    """ Downloads an image and decodes it, scaled to the given size.

    :param url: URL of the image to download.
    :param width: Width, in pixels, of the resulting image.
    :param height: Height, in pixels, of the resulting image.
    :returns: The decoded wx.Image, or None if it could not be downloaded or decoded.
    """
    if not url:
        return None
    try:
        response = requests.get(url, timeout=10)
        response.raise_for_status()
    except requests.exceptions.RequestException:
        log.exception("Unable to download image from %s", url)
        return None
    return load_scaled_image(response.content, width, height)


class UpdateProfileDialog(wx.Dialog):
    """
    A dialog for user to update his / her profile details.
    layout is:
    ```
    header
    avatar
    name
    bio
    meta data
    ```
    """

    def __init__(self, display_name: str, note: str, header: str, avatar: str, fields: list, locked: bool, bot: bool, discoverable: bool):
        """Initialize update profile dialog
        Parameters:
        - display_name: The user's display name to show in the display name field
        - note: The users bio to show in the bio field
        - header: the users header pic link
        - avatar: The users avatar pic link
        """
        super().__init__(parent=None)
        self.SetTitle(_("Update Profile"))
        self.header = header
        self.avatar = avatar

        panel = wx.Panel(self)
        sizer = wx.BoxSizer(wx.VERTICAL)

        # create widgets
        display_name_label = wx.StaticText(panel, label=_("&Display Name"))
        self.display_name = wx.TextCtrl(panel, value=display_name, style= wx.TE_PROCESS_ENTER, size=(200, 30))
        name_sizer = wx.BoxSizer(wx.HORIZONTAL)
        name_sizer.Add(display_name_label, wx.SizerFlags().Center())
        name_sizer.Add(self.display_name, wx.SizerFlags().Center())
        sizer.Add(name_sizer, wx.CENTER)

        bio_label = wx.StaticText(panel, label=_("&Bio"))
        self.bio = wx.TextCtrl(panel, value=note, style=wx.TE_PROCESS_ENTER | wx.TE_MULTILINE, size=(400, 60))
        bio_sizer = wx.BoxSizer(wx.HORIZONTAL)
        bio_sizer.Add(bio_label, wx.SizerFlags().Center())
        bio_sizer.Add(self.bio, wx.SizerFlags().Center())
        sizer.Add(bio_sizer, wx.CENTER)

        # header
        header_label = wx.StaticText(panel, label=_("Header"))
        header_bitmap = download_scaled_image(self.header, 300, 100)
        if header_bitmap is None:
            # The image is unavailable or in a format we cannot decode, so show an empty placeholder.
            self.header_image = wx.StaticBitmap(panel)
        else:
            self.header_image = wx.StaticBitmap(panel, bitmap=header_bitmap.ConvertToBitmap())

        self.header_image.AcceptsFocusFromKeyboard = return_true
        self.change_header = wx.Button(panel, label=_("Change &header"))
        header_sizer = wx.BoxSizer(wx.HORIZONTAL)
        header_sizer.Add(header_label, wx.SizerFlags().Center())
        header_sizer.Add(self.header_image, wx.SizerFlags().Center())
        header_sizer.Add(self.change_header, wx.SizerFlags().Center())
        sizer.Add(header_sizer, wx.CENTER)

        # avatar
        avatar_label = wx.StaticText(panel, label=_("Avatar"))
        avatar_bitmap = download_scaled_image(self.avatar, 150, 150)
        if avatar_bitmap is None:
            # The image is unavailable or in a format we cannot decode, so show an empty placeholder.
            self.avatar_image = wx.StaticBitmap(panel)
        else:
            self.avatar_image = wx.StaticBitmap(panel, bitmap=avatar_bitmap.ConvertToBitmap())

        self.avatar_image.AcceptsFocusFromKeyboard = return_true
        self.change_avatar = wx.Button(panel, label=_("Change &avatar"))
        avatar_sizer = wx.BoxSizer(wx.HORIZONTAL)
        avatar_sizer.Add(avatar_label, wx.SizerFlags().Center())
        avatar_sizer.Add(self.avatar_image, wx.SizerFlags().Center())
        avatar_sizer.Add(self.change_avatar, wx.SizerFlags().Center())
        sizer.Add(avatar_sizer, wx.CENTER)

        self.fields = []
        for i in range(1, 5):
            field_sizer = wx.BoxSizer(wx.HORIZONTAL)
            field_label = wx.StaticText(panel, label=_("Field &{}: Label").format(i))
            field_sizer.Add(field_label, wx.SizerFlags().Center().Border(wx.ALL, 5))

            label_textctrl = wx.TextCtrl(panel, style=wx.TE_PROCESS_ENTER | wx.TE_MULTILINE, size=(200, 30))
            if i <= len(fields):
                label_textctrl.SetValue(fields[i-1][0])
            field_sizer.Add(label_textctrl, wx.SizerFlags().Expand().Border(wx.ALL, 5))

            content_label = wx.StaticText(panel, label=_("Content"))
            field_sizer.Add(content_label, wx.SizerFlags().Center().Border(wx.ALL, 5))

            content_textctrl = wx.TextCtrl(panel, style=wx.TE_PROCESS_ENTER | wx.TE_MULTILINE, size=(400, 60))
            if i <= len(fields):
                content_textctrl.SetValue(fields[i-1][1])
            field_sizer.Add(content_textctrl, wx.SizerFlags().Expand().Border(wx.ALL, 5))
            sizer.Add(field_sizer, 0, wx.CENTER)
            self.fields.append((label_textctrl, content_textctrl))

        self.locked = wx.CheckBox(panel, label=_("&Private account"))
        self.locked.SetValue(locked)
        self.bot = wx.CheckBox(panel, label=_("B&ot account"))
        self.bot.SetValue(bot)
        self.discoverable = wx.CheckBox(panel, label=_("&Discoverable account"))
        self.discoverable.SetValue(discoverable)
        sizer.Add(self.locked, wx.SizerFlags().Expand().Border(wx.ALL, 5))
        sizer.Add(self.bot, wx.SizerFlags().Expand().Border(wx.ALL, 5))
        sizer.Add(self.discoverable, wx.SizerFlags().Expand().Border(wx.ALL, 5))

        ok = wx.Button(panel, wx.ID_OK, _(u"&OK"))
        ok.SetDefault()
        cancel = wx.Button(panel, wx.ID_CANCEL, _("&Close"))
        self.SetEscapeId(cancel.GetId())
        action_sizer = wx.BoxSizer(wx.HORIZONTAL)
        action_sizer.Add(ok, wx.SizerFlags().Center())
        action_sizer.Add(cancel, wx.SizerFlags().Center())
        sizer.Add(action_sizer, wx.CENTER)
        panel.SetSizer(sizer)
        sizer.Fit(self)
        self.Center()

        # manage events
        ok.Bind(wx.EVT_BUTTON, self.on_ok)
        self.change_header.Bind(wx.EVT_BUTTON, self.on_change_header)
        self.change_avatar.Bind(wx.EVT_BUTTON, self.on_change_avatar)

        self.AutoLayout = True

    def on_ok(self, *args):
        """Method called when user clicks ok in dialog"""
        self.data = {
                'display_name': self.display_name.GetValue(),
                'note': self.bio.GetValue(),
                'header': self.header,
                'avatar': self.avatar,
                'fields': [(label.GetValue(), content.GetValue()) for label, content in self.fields if label.GetValue() and content.GetValue()],
                'locked': self.locked.GetValue(),
                'bot': self.bot.GetValue(),
                'discoverable': self.discoverable.GetValue(),
                }
        self.EndModal(wx.ID_OK)

    def on_change_header(self, *args):
        """Display a dialog for the user to choose a picture and update the
        appropriate attribute"""
        dlg = wx.FileDialog(self, _("Select header image - max 2MB"), wildcard=IMAGE_WILDCARD)
        if dlg.ShowModal() == wx.CLOSE:
            return
        if os.path.getsize(dlg.GetPath()) > 2097152:
            # File size exceeds the limit
            message = _("The selected file is larger than 2MB. Do you want to select another file?")
            caption = _("File more than 2MB")
            style = wx.YES_NO | wx.ICON_WARNING

            # Display the message box
            result = wx.MessageBox(message, caption, style)
            return self.on_change_header() if result == wx.YES else None

        self.header = dlg.GetPath()
        image = load_scaled_image(self.header, 150, 150)
        if image is None:
            return commonMessageDialogs.unsupported_image()
        self.header_image.SetBitmap(image.ConvertToBitmap())

    def on_change_avatar(self, *args):
        """Display a dialog for the user to choose a picture and update the
        appropriate attribute"""
        dlg = wx.FileDialog(self, _("Select avatar image - max 2MB"), wildcard=IMAGE_WILDCARD)
        if dlg.ShowModal() == wx.CLOSE:
            return
        if os.path.getsize(dlg.GetPath()) > 2097152:
            # File size exceeds the limit
            message = _("The selected file is larger than 2MB. Do you want to select another file?")
            caption = _("File more than 2MB")
            style = wx.YES_NO | wx.ICON_WARNING

            # Display the message box
            result = wx.MessageBox(message, caption, style)
            return self.on_change_avatar() if result == wx.YES else None

        self.avatar = dlg.GetPath()
        image = load_scaled_image(self.avatar, 150, 150)
        if image is None:
            return commonMessageDialogs.unsupported_image()
        self.avatar_image.SetBitmap(image.ConvertToBitmap())
