import gi
import matplotlib
matplotlib.use('GTK3Agg')
from matplotlib.figure import Figure
from matplotlib.backends.backend_gtk3agg import FigureCanvasGTK3Agg as FigureCanvas

from gi.repository import Gtk, Gdk, GLib
import pyperclip
import time

class AnimationConfigurator(Gtk.Window):
    def __init__(self):
        super().__init__(title="Hyprland Animation Configurator")
        self.set_default_size(600, 600)

        self.curves = {
            "default": (0.25, 0.25, 0.75, 0.75),
            "soft": (0.25, 0.8, 0.25, 1),
            "jellyFast": (0.25, 1.1, 0.4, 1.2),
            "bounce": (0.34, 1.56, 0.64, 1.0),
            "snappy": (0.45, 1.8, 0.4, 1),
            "smoothOut": (0.3, 1, 0.6, 1),
        }

        self.styles = ["slide", "popin", "gnomed", "fade", "slidefade", "slidevert", "slidefadevert"]

        main_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6)
        main_box.set_margin_top(10)
        main_box.set_margin_bottom(10)
        main_box.set_margin_start(10)
        main_box.set_margin_end(10)

        # Dropdown de curvas
        self.curve_combo = Gtk.ComboBoxText()
        for name in self.curves:
            self.curve_combo.append_text(name)
        self.curve_combo.set_active(0)
        self.curve_combo.connect("changed", self.update_curve)
        main_box.pack_start(Gtk.Label(label="Curva Bézier"), False, False, 0)
        main_box.pack_start(self.curve_combo, False, False, 0)

        # Slider de velocidad
        self.speed_adjustment = Gtk.Adjustment(5, 1, 20, 1, 0, 0)
        self.speed_slider = Gtk.Scale(orientation=Gtk.Orientation.HORIZONTAL, adjustment=self.speed_adjustment)
        self.speed_slider.set_digits(0)
        main_box.pack_start(Gtk.Label(label="Velocidad (ds: 1ds = 100ms)"), False, False, 0)
        main_box.pack_start(self.speed_slider, False, False, 0)

        # Dropdown de estilo
        self.style_combo = Gtk.ComboBoxText()
        for s in self.styles:
            self.style_combo.append_text(s)
        self.style_combo.set_active(3)  # 'fade'
        main_box.pack_start(Gtk.Label(label="Estilo"), False, False, 0)
        main_box.pack_start(self.style_combo, False, False, 0)

        # Preview Bézier con matplotlib
        self.figure = Figure(figsize=(4, 2))
        self.ax = self.figure.add_subplot(111)
        self.canvas = FigureCanvas(self.figure)
        self.update_curve()  # inicializa la curva
        main_box.pack_start(self.canvas, True, True, 0)

        # Botón para generar línea
        self.output_label = Gtk.Label(label="")
        gen_button = Gtk.Button(label="Copiar línea de configuración")
        gen_button.connect("clicked", self.copy_line)
        main_box.pack_start(gen_button, False, False, 5)
        main_box.pack_start(self.output_label, False, False, 5)

        # Botones para previews
        preview_buttons = Gtk.Box(spacing=10)
        fade_button = Gtk.Button(label="Previsualizar fade")
        fade_button.connect("clicked", self.run_fade_preview)
        slide_button = Gtk.Button(label="Previsualizar slide")
        slide_button.connect("clicked", self.run_slide_preview)
        preview_buttons.pack_start(fade_button, True, True, 0)
        preview_buttons.pack_start(slide_button, True, True, 0)
        main_box.pack_start(preview_buttons, False, False, 10)

        # Área de previsualización
        self.preview_area = Gtk.Fixed()
        self.preview_box = Gtk.EventBox()
        self.preview_box.set_size_request(100, 50)
        self.preview_box.override_background_color(Gtk.StateFlags.NORMAL, Gdk.RGBA(0.2, 0.6, 1.0, 1.0))
        self.preview_area.put(self.preview_box, -110, 0)
        main_box.pack_start(self.preview_area, True, True, 0)

        self.add(main_box)
        self.show_all()

    def bezier_point(self, t, p0, p1, p2, p3):
        return (
            (1 - t)**3 * p0 + 3 * (1 - t)**2 * t * p1 + 3 * (1 - t) * t**2 * p2 + t**3 * p3
        )

    def update_curve(self, *_):
        name = self.curve_combo.get_active_text()
        if not name:
            return
        x1, y1, x2, y2 = self.curves[name]
        ts = [t / 100 for t in range(101)]
        xs = [self.bezier_point(t, 0, x1, x2, 1) for t in ts]
        ys = [self.bezier_point(t, 0, y1, y2, 1) for t in ts]
        self.ax.clear()
        self.ax.plot(xs, ys)
        self.ax.set_title(f"Curva: {name}")
        self.canvas.draw()

    def copy_line(self, *_):
        curve = self.curve_combo.get_active_text()
        speed = int(self.speed_slider.get_value())
        style = self.style_combo.get_active_text()
        line = f"animation = windows, 1, {speed}, {curve}, {style}"
        pyperclip.copy(line)
        self.output_label.set_text(f"Copiado: {line}")

    def run_fade_preview(self, *_):
        name = self.curve_combo.get_active_text()
        _, y1, y2, _ = 0, *self.curves[name][1:3], 1
        duration = int(self.speed_slider.get_value()) * 100
        steps = 60
        interval = duration / steps

        t = 0
        def update():
            nonlocal t
            t += 1 / steps
            if t > 1:
                t = 1
            alpha = self.bezier_point(t, 0, y1, y2, 1)
            self.preview_box.override_background_color(Gtk.StateFlags.NORMAL, Gdk.RGBA(0.2, 0.6, 1.0, alpha))
            return t < 1

        self.preview_box.override_background_color(Gtk.StateFlags.NORMAL, Gdk.RGBA(0.2, 0.6, 1.0, 0))
        GLib.timeout_add(int(interval), update)

    def run_slide_preview(self, *_):
        name = self.curve_combo.get_active_text()
        x1, _, x2, _ = self.curves[name]
        duration = int(self.speed_slider.get_value()) * 100
        steps = 60
        interval = duration / steps
        width = self.preview_area.get_allocated_width()
        end_x = (width - 100) // 2

        t = 0
        def update():
            nonlocal t
            t += 1 / steps
            if t > 1:
                t = 1
            x = self.bezier_point(t, -110, x1 * end_x, x2 * end_x, end_x)
            self.preview_area.move(self.preview_box, int(x), 0)
            return t < 1

        self.preview_area.move(self.preview_box, -110, 0)
        GLib.timeout_add(int(interval), update)


def main():
    win = AnimationConfigurator()
    Gtk.main()


if __name__ == "__main__":
    main()
