from gettext import gettext as _
from giara.path_utils import is_image, is_media, is_gif
from giara.download_manager import download_img, download_video
from gi.repository import Gtk, GLib, Gdk, Gio
from praw.models import Comment, Submission, Message
from threading import Thread
from giara.new_post_window import EditWindow
from giara.picture_view import PictureView
from giara.flair_label import FlairLabel
from giara.time_utils import humanize_utc_timestamp
from giara.confManager import ConfManager
from giara.simple_avatar import SimpleAvatar
from giara.children_box import ChildrenBox
from giara.picture_gallery import PictureGallery
from giara.imgviewer import ImageViewer
from giara.network_cache import CachedSubreddit
from giara.common_functions import get_subreddit_icon


def empty_container(cont: Gtk.Widget) -> None:
    child = cont.get_first_child()
    while child is not None:
        cont.remove(child)
        # child.destroy()
        del child
        child = cont.get_first_child()


class InteractiveEntityBox(ChildrenBox):
    def __init__(self, builder, **kwargs):
        super().__init__(vexpand=False, hexpand=True, **kwargs)
        self.entity = None
        self.builder = builder
        self.confman = ConfManager()
        self.me = self.confman.reddit_user_me

        self.save_btn = self.builder.get_object('save_btn')
        self.save_btn.connect('clicked', self.on_save_clicked)
        self.upvotes_label = self.builder.get_object('upvotes_label')
        self.upvote_btn = self.builder.get_object('upvote_btn')
        self.downvote_btn = self.builder.get_object('downvote_btn')

        self.upvote_btn.connect('clicked', self.on_upvote_btn_clicked)
        self.downvote_btn.connect('clicked', self.on_downvote_btn_clicked)

        self.delete_btn = self.builder.get_object('delete_btn')
        self.share_btn = self.builder.get_object('share_btn')
        self.edit_btn = self.builder.get_object('edit_btn')

        self.main_box = self.builder.get_object('main_box')
        self.append(self.main_box)

        self.author_flairs_container = self.builder.get_object(
            'author_flairs_container'
        )

    def set_entity(self, entity):
        self.entity = entity
        if (
                hasattr(self.entity, 'subreddit') and not
                hasattr(self.entity, 'cached_subreddit')
        ):
            self.entity.cached_subreddit = CachedSubreddit(
                self.entity.subreddit, self.entity.subreddit_id
            )
        self.color_up_down_btns()
        self.color_saved_btn()
        if hasattr(self.entity, 'permalink'):
            self.share_btn.set_visible(True)
            self.share_btn.connect('clicked', self.copy_link)
        else:
            self.share_btn.set_visible(False)
        self.show_hide_edit_delete()
        if (
                self.author_flairs_container is not None and
                self.entity.author_flair_text  # can be None or empty string
        ):
            empty_container(self.author_flairs_container)
            subreddit = None
            if hasattr(self.entity, 'subreddit'):
                subreddit = self.entity.subreddit
            self.author_flairs_container.append(
                FlairLabel(
                    self.entity.author_flair_text,
                    self.entity.author_flair_background_color,
                    self.entity.author_flair_text_color,
                    subreddit=subreddit
                )
            )

    def show_hide_edit_delete(self):
        if self.entity is None:
            return

        def af():
            if self.edit_btn:
                show_edit = (
                    self.entity.author is not None and
                    self.entity.author.fullname == self.me.fullname and
                    (
                        isinstance(self.entity, Comment) or
                        (
                            isinstance(self.entity, Submission) and
                            self.entity.is_self
                        )
                    )
                )
                GLib.idle_add(edit_cb, show_edit)
            if (
                    hasattr(self.entity, 'delete') and
                    hasattr(self.entity, 'author') and
                    self.entity.author == self.me
            ):
                GLib.idle_add(delete_cb)

        def edit_cb(show_edit):
            self.edit_btn.set_visible(show_edit)
            if show_edit:
                self.edit_btn.connect('clicked', self.on_edit_clicked)

        def delete_cb():
            self.delete_btn.set_visible(True)
            self.delete_btn.connect('clicked', self.on_delete_clicked)

        Thread(target=af, daemon=True).start()

    def on_delete_clicked(self, *args):
        if self.entity is None:
            return
        # TODO: fix message dialog
        confirm_dialog = Gtk.MessageDialog(
            transient_for=self.get_root(),
            modal=True,
            message_type=Gtk.MessageType.QUESTION,
            buttons=Gtk.ButtonsType.YES_NO,
            text=_('Are you sure you want to delete this item?')
        )

        def on_response(dialog, res):
            dialog.close()
            if res == Gtk.ResponseType.YES:
                self.entity.delete()
                if hasattr(self, 'refresh_func'):
                    self.refresh_func(wait_for_comments_update=True)

        confirm_dialog.connect('response', on_response)
        confirm_dialog.present()
        confirm_dialog.show()

    def on_edit_clicked(self, *args):
        if self.entity is None:
            return
        win = EditWindow(
            self.entity,
            lambda *args: (
                self.refresh_func(wait_for_comments_update=True)
                if hasattr(self, 'refresh_func') else None
            )
        )
        win.set_transient_for(self.get_root())
        win.present()
        win.show()

    def copy_link(self, *args):
        if self.entity is None:
            return
        Gdk.Display.get_default().get_clipboard().set(
            'https://reddit.com' + (
                '/'
                if self.entity.permalink[0] != '/' else ''
            ) + self.entity.permalink
        )
        self.get_root().main_ui.show_notification(
            _('Link copied to clipboard')
        )

    def on_save_clicked(self, *args):
        if self.entity is None:
            return

        def af():
            if self.entity.saved:
                self.entity.unsave()
            else:
                self.entity.save()
            self.entity._fetch()
            GLib.idle_add(cb)

        def cb():
            self.color_saved_btn()
            self.save_btn.set_sensitive(True)

        self.save_btn.set_sensitive(False)
        Thread(target=af, daemon=True).start()

    def color_saved_btn(self):
        if self.entity is None:
            return
        if hasattr(self.entity, 'saved'):
            self.save_btn.set_visible(True)
            if self.entity.saved:
                self.save_btn.get_style_context().add_class('blue')
            else:
                self.save_btn.get_style_context().remove_class('blue')
        else:
            self.save_btn.set_visible(False)

    def on_upvote_btn_clicked(self, *args):
        if self.entity is None:
            return

        def af():
            if self.entity.likes:
                self.entity.clear_vote()
                self.entity.likes
            else:
                self.entity.upvote()
            self.entity._fetch()
            GLib.idle_add(cb)

        def cb():
            self.color_up_down_btns()
            self.downvote_btn.set_sensitive(True)
            self.upvote_btn.set_sensitive(True)

        self.upvote_btn.set_sensitive(False)
        self.downvote_btn.set_sensitive(False)
        Thread(target=af, daemon=True).start()

    def on_downvote_btn_clicked(self, *args):
        if self.entity is None:
            return

        def af():
            if self.entity.likes or self.entity.likes is None:
                self.entity.downvote()
            else:
                self.entity.clear_vote()
            self.entity._fetch()
            GLib.idle_add(cb)

        def cb():
            self.color_up_down_btns()
            self.downvote_btn.set_sensitive(True)
            self.upvote_btn.set_sensitive(True)

        self.upvote_btn.set_sensitive(False)
        self.downvote_btn.set_sensitive(False)
        Thread(target=af, daemon=True).start()

    def color_up_down_btns(self):
        if self.entity is None:
            return
        # also update ups label
        self.upvotes_label.set_text(str(self.entity.score))
        upvote_style_context = self.upvote_btn.get_style_context()
        downvote_style_context = self.downvote_btn.get_style_context()
        if self.entity.likes is None:  # None = no interaction
            upvote_style_context.remove_class('blue')
            downvote_style_context.remove_class('red')
        elif self.entity.likes:  # True = upvote
            upvote_style_context.add_class('blue')
            downvote_style_context.remove_class('red')
        else:  # False = downvote
            upvote_style_context.remove_class('blue')
            downvote_style_context.add_class('red')


class CommonPostBox(InteractiveEntityBox):
    def __init__(self, builder, **kwargs):
        super().__init__(builder, **kwargs)
        self.post = None
        self.title_label = self.builder.get_object('title_label')
        self.pinned_icon = self.builder.get_object('pinned_icon')
        self.datetime_label = self.builder.get_object('datetime_label')
        self.subreddit_label = self.builder.get_object('subreddit_label')
        self.op_label = self.builder.get_object('op_label')
        self.open_media_btn = self.builder.get_object('open_media_btn')
        self.open_media_btn.connect(
            'clicked',
            lambda *args: self.open_media()
        )
        self.flairs_container = self.builder.get_object('flairs_container')
        self.image_container = self.builder.get_object('image_container')
        self.image_container_child = None
        self.image_container_gallery = None
        self.open_link_btn = self.builder.get_object('open_link_btn')
        self.avatar_container = self.builder.get_object('avatar_container')
        self.avatar = None
        self.can_open_media = False

    def set_post(self, post):
        self.set_entity(post)

    def hide_images(self):
        for w in (self.image_container_child, self.image_container_gallery):
            if w is not None:
                w.hide()

    def set_entity(self, entity):
        # empty_container(self.image_container)
        self.hide_images()
        self.post = entity
        super().set_entity(entity)
        if isinstance(self.post, Submission):
            self.title_label.set_text(self.post.title)
            self.pinned_icon.set_visible(self.post.stickied)
        elif isinstance(self.post, Comment):
            self.title_label.set_ellipsize(True)
            self.title_label.set_lines(2)
            self.title_label.set_text(
                _('Comment: ')+self.post.body.replace('\n', '  ')
            )
        else:
            self.title_label.set_text(self.post.body)
        self.datetime_label.set_text(
            humanize_utc_timestamp(self.post.created_utc)
        )
        if isinstance(self.post, Message):
            self.subreddit_label.set_text(_('Message'))
        else:
            self.subreddit_label.set_text(
                self.post.cached_subreddit.display_name_prefixed
            )
        self.op_label.set_text(
            f'u/{self.post.author.name}'
            if self.post.author is not None else _('Author unknown')
        )
        avatar_title = (
            self.post.cached_subreddit.display_name
            if self.post.cached_subreddit is not None
            else self.post.author.name
        )
        if self.avatar is None:
            self.avatar = SimpleAvatar(
                42,
                avatar_title,
                self.get_subreddit_icon
            )
            self.avatar_container.append(self.avatar)
        else:
            self.avatar.load_avatar(
                avatar_title, self.get_subreddit_icon
            )

        self.can_open_media = isinstance(self.post, Submission) and (
            self.post.is_video or
            self.post.is_reddit_media_domain or
            'reddit.com/gallery/' in self.post.url or
            is_media(self.post.url)
        )
        self.is_video = (
            isinstance(self.post, Submission) and
            (self.post.is_video or 'https://v.redd.it' in self.post.url)
        )
        self.open_media_btn.set_visible(self.can_open_media)
        empty_container(self.flairs_container)
        if isinstance(self.post, Submission):
            if self.post.over_18:
                self.flairs_container.append(FlairLabel.new_nsfw())
            type_flair = None
            if self.post.is_self:
                type_flair = FlairLabel.new_type_text()
            elif self.is_video:
                type_flair = FlairLabel.new_type_video()
            elif self.post.is_reddit_media_domain:
                type_flair = FlairLabel.new_type_image()
            else:
                type_flair = FlairLabel.new_type_link()
            self.flairs_container.append(type_flair)
            if self.post.link_flair_text:
                self.flairs_container.append(
                    FlairLabel.new_from_post(self.post)
                )
        self.set_post_image()
        if hasattr(self.post, 'url'):
            self.open_link_btn.set_visible(True)
            self.open_link_btn.connect(
                'clicked',
                self.open_link
            )
        else:
            self.open_link_btn.set_visible(False)

    def open_link(self, *args):
        if self.post is None or self.post.url is None:
            return
        url = self.post.url
        if not ('http://' in url or 'https://' in url):
            reddit = self.confman.reddit
            self.get_root().main_ui.deck.show_post(reddit.submission(url=(
                'https://reddit.com' + ('/' if url[0] != '/' else '') + url
            )))
        if self.confman.conf['twitter2nitter']:
            for pfx in [p + 'twitter.com' for p in ('', 'www.', 'mobile.')]:
                if f'://{pfx}' in url:
                    nit = self.confman.conf['nitter_instance']
                    url = url.replace(f'://{pfx}', f'://{nit}')
                    break
        if self.confman.conf['youtube2invidious']:
            inv = self.confman.conf['invidious_instance']
            for pfx in [p + 'youtube.com' for p in ('', 'www.', 'm.')]:
                if f'://{pfx}' in url:
                    url = url.replace(f'://{pfx}', f'://{inv}')
                    break
        Gio.AppInfo.launch_default_for_uri(url)

    def get_subreddit_icon(self):
        if self.post is None:
            return
        return get_subreddit_icon(self.post.cached_subreddit)

    def set_post_image(self):
        if self.post is None:
            return

        def af():
            post_img = self.get_post_image_filename()
            blur = self.post.over_18
            if post_img is None:
                GLib.idle_add(cb_hide_all)
            elif isinstance(post_img, list):
                GLib.idle_add(cb_gallery, post_img, blur)
            else:
                GLib.idle_add(cb, post_img, blur)

        def cb_hide_all():
            self.image_container.set_visible(False)

        def cb_gallery(images, blur):
            if self.image_container_child is not None:
                self.image_container_child.set_visible(False)
            if self.image_container_gallery is None:
                self.image_container_gallery = PictureGallery(
                    images, self.open_media, blur=blur
                )
                if hasattr(self.image_container, 'set_child'):
                    self.image_container.set_child(
                        self.image_container_gallery
                    )
                else:
                    self.image_container.append(self.image_container_gallery)
            else:
                self.image_container_gallery.set_pictures(
                    images, blur=blur
                )
                self.image_container_gallery.set_visible(True)

        def cb(post_img, blur):
            if self.image_container_gallery is not None:
                self.image_container_gallery.set_visible(False)
            self.image_container.set_visible(True)
            if self.image_container_child is None:
                self.image_container_child = PictureView(
                    post_img, self.is_video or is_gif(post_img),
                    self.open_media, blur=blur
                )
                if hasattr(self.image_container, 'set_child'):
                    self.image_container.set_child(self.image_container_child)
                else:
                    self.image_container.append(self.image_container_child)
            else:
                self.image_container_child.set_file(
                    post_img, self.is_video, blur=blur
                )
                self.image_container_child.set_visible(True)
            self.image_container.show()

        Thread(target=af, daemon=True).start()

    def open_media(self):
        if self.post is None:
            return
        if not self.can_open_media:
            return self.open_link()

        def af():
            images = None
            if self.is_video:
                images = download_video(
                    self.post.media['reddit_video']['fallback_url']
                    if self.post.media
                    else self.post.url+'/DASH_1080.mp4'
                )
            elif 'reddit.com/gallery/' in self.post.url:
                if self.image_container_gallery is not None:
                    images = self.image_container_gallery.pictures
            else:
                images = download_img(self.post.url)
            if images is not None:
                GLib.idle_add(cb, images)

        def cb(images):
            if not isinstance(images, list):
                images = [images]
            if len(images) == 1 and \
                    (not is_image(images[0]) or is_gif(images[0])):
                Gio.AppInfo.launch_default_for_uri(
                    GLib.filename_to_uri(images[0])
                )
                return
            ImageViewer(self.get_root(), images).present()

        Thread(target=af, daemon=True).start()

    def get_post_image_filename(self):
        if self.post is None:
            return
        if isinstance(self.post, Comment):
            return None
        image = 'No image'
        try:
            # image can be the url
            image = self.post.url
            # if the url isn't directly an image
            if not is_image(image):
                # maybe it's a gallery?
                if 'reddit.com/gallery/' in self.post.url:
                    # get the media ids
                    media_ids = [
                        item['media_id']
                        for item in self.post.gallery_data['items']
                    ]
                    # get the corresponding urls for each id
                    media_urls = [
                        self.post.media_metadata[mid]['s']['u']
                        for mid in media_ids
                    ]
                    return [download_img(url) for url in media_urls]
                if not hasattr(self.post, 'preview'):
                    return None
                image = max([
                    p for p in self.post.preview['images'][0]['resolutions']
                ], key=lambda prev: prev['width'])['url']
            if is_image(image):
                image_path = download_img(image)
                return image_path
        except Exception:
            # import traceback
            # traceback.print_exc()
            # print(dir(self.post))
            print(f'Error creating pixbuf for post image `{image}`')
            return None
