from typing import Optional

from gi.repository import Gdk, GdkPixbuf, Gtk


class SpinnerPicture(Gtk.Bin):
    def __init__(
        self,
        loading: bool = True,
        spinner_name: str = None,
        **kwargs,
    ):
        """An picture with a loading overlay."""
        super().__init__()
        self.filename: Optional[str] = None
        self.pixbuf = None

        self.offset = (0, 0)
        self.sized_pixbuf = None

        self.spinner = Gtk.Spinner(
            name=spinner_name,
            active=loading,
            halign=Gtk.Align.CENTER,
            valign=Gtk.Align.CENTER,
        )
        self.add(self.spinner)

    def set_from_file(self, filename: Optional[str]):
        """Set the picture to the given filename."""
        filename = filename or None
        if self.filename == filename:
            return

        self.filename = filename

        if self.filename:
            self.pixbuf = GdkPixbuf.Pixbuf.new_from_file(self.filename)
        else:
            self.pixbuf = None
        self._update_sized_pixbuf()

    def set_loading(self, loading_status: bool):
        if loading_status:
            self.spinner.start()
            self.spinner.show()
        else:
            self.spinner.stop()
            self.spinner.hide()

    def do_size_allocate(self, allocation):
        Gtk.Bin.do_size_allocate(self, allocation)

        self._update_sized_pixbuf()

    def do_draw(self, cr):
        if self.sized_pixbuf:
            Gdk.cairo_set_source_pixbuf(cr, self.sized_pixbuf, self.offset[0], self.offset[1])
            cr.paint()

        Gtk.Bin.do_draw(self, cr)

    def _update_sized_pixbuf(self):
        if self.pixbuf is None:
            self.sized_pixbuf = None
            return

        pix_width = self.pixbuf.get_width()
        pix_height = self.pixbuf.get_height()
        alloc_width = self.get_allocated_width()
        alloc_height = self.get_allocated_height()

        scale = max(alloc_width / pix_width, alloc_height / pix_height)
        scaled_width = pix_width * scale
        scaled_height = pix_height * scale
        self.sized_pixbuf = self.pixbuf.scale_simple(scaled_width, scaled_height, GdkPixbuf.InterpType.BILINEAR)

        self.offset = (
            (alloc_width - scaled_width) / 2,
            (alloc_height - scaled_height) / 2,
        )
