from giara.constants import RESOURCE_PREFIX
from gi.repository import Gtk, Gdk, Gio, Graphene, GLib
from giara.confManager import ConfManager
from threading import Thread
from math import ceil


class PictureViewInner(Gtk.Button):
    def __init__(self, parent_p):
        super().__init__(hexpand=True, vexpand=True)
        self.parent_p = parent_p
        self.get_style_context().add_class('invisible-btn')
        self.connect('clicked', self.parent_p.open_image)


class PictureView(Gtk.Widget):
    def __init__(self, path, is_video, open_media_func=None, blur=False):
        super().__init__(
            overflow=Gtk.Overflow.HIDDEN, vexpand=True,
            hexpand=True,
            valign=Gtk.Align.CENTER
        )
        for c in ('frame', 'picture-rounded'):
            self.get_style_context().add_class(c)
        self.open_media_func = open_media_func
        self.confman = ConfManager()
        self.confman.connect(
            'on_max_picture_height_changed',
            lambda *args: self.queue_resize()
        )
        self.texture = None
        self.aspect_ratio = None
        self.child = None
        self.set_child(PictureViewInner(self))
        self.set_file(path, is_video, blur=blur)

    def set_child(self, child):
        self.child = child
        self.child.set_parent(self)

    def remove(self, child):
        child.unparent()
        self.child = None

    def open_image(self, *args):
        if self.open_media_func is not None:
            self.open_media_func()

    def set_file(self, path, is_video, blur=False):
        self.path = path
        self.is_video = is_video
        self.blur = blur and self.confman.conf['blur_nsfw']
        gio_file = Gio.File.new_for_path(self.path)

        def af():
            self.texture = self.texture = Gdk.Texture.new_from_file(gio_file)
            GLib.idle_add(cb)

        def cb():
            if self.texture is None:
                return
            self.aspect_ratio = self.texture.get_intrinsic_aspect_ratio()
            if self.is_video:
                self.video_icon_texture = Gdk.Texture.new_from_resource(
                    f'{RESOURCE_PREFIX}/icons/video-icon.svg'
                )
                # max prevents the scale from being 0
                self.video_icon_size = 64 * max(self.get_scale_factor(), 1)
            self.queue_draw()
            self.queue_resize()

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

    def do_get_request_mode(self, *args):
        return Gtk.SizeRequestMode.HEIGHT_FOR_WIDTH

    def do_snapshot(self, snapshot):
        if self.texture is None or self.aspect_ratio is None:
            return
        width = self.get_width()
        height = width / self.aspect_ratio
        if self.blur:
            snapshot.push_blur(100.0)
        self.texture.snapshot(
            snapshot,
            width, height
        )
        if self.blur:
            snapshot.pop()
        if self.is_video:
            r = Graphene.Rect.alloc()
            r.init(
                (self.get_width()/2)-(self.video_icon_size/2),
                (self.get_height()/2)-(self.video_icon_size/2),
                self.video_icon_size, self.video_icon_size
            )
            snapshot.append_texture(
                self.video_icon_texture,
                r
            )
        if self.child is not None:
            self.snapshot_child(self.child, snapshot)

    def get_real_size(self, w, h):
        meas_w = self.measure(Gtk.Orientation.HORIZONTAL, h)
        w = min(meas_w[1], max(w, meas_w[0]))
        h = self.measure(Gtk.Orientation.VERTICAL, w)[1]
        return w, h

    def do_size_allocate(self, w, h, baseline):
        assert(self.child is not None)
        w, h = self.get_real_size(w, h)
        rect = Gdk.Rectangle()
        rect.height = h
        rect.width = w
        rect.x = 0
        rect.y = 0
        return self.child.size_allocate(
            rect, baseline
        )

    def do_measure(self, orientation, for_size):
        child_measure = (
            self.child.measure(orientation, for_size)
            if self.child is not None else (0, 0, -1, -1)
        )
        if orientation == Gtk.Orientation.VERTICAL:
            if for_size == -1:
                return (0, 0, -1, -1)
            if not self.texture:
                return (0, 0, -1, -1)
            aspect = self.aspect_ratio or 1
            # max prevents the height to be lower than the minimum
            # that I defined
            # height = min(max(min(
            #     ceil(for_size / aspect),
            #     self.confman.conf['max_picture_height']
            # ), 100), 1200)
            cw, ch = self.texture.compute_concrete_size(
                for_size, 0, 1200, 1200
            )
            ch = max(min(ceil(ch), 1200), 1)
            # TODO: find proper solution
            # this is a hack to prevent gtk critical
            # allocation height too small
            # height = max(child_measure[0], height)  # - 50
            return (0, ch, -1, -1)
        else:
            return (
                0,
                1200,  # max(child_measure[1], 1200),
                -1, -1
            )
