import { Gtk } from "astal/gtk3";
import cairo from "cairo";
import AstalCava from "gi://AstalCava";
import PangoCairo from "gi://PangoCairo";

export default () => (
    <drawingarea
        className="visualiser"
        setup={self => {
            const cava = AstalCava.get_default();

            if (cava) {
                cava.set_stereo(true);
                cava.set_noise_reduction(0.77);
                cava.set_input(AstalCava.Input.PIPEWIRE);

                self.hook(cava, "notify::values", () => self.queue_draw());
                self.connect("size-allocate", () => {
                    const width = self.get_allocated_width();
                    const barWidth = self
                        .get_style_context()
                        .get_property("min-width", Gtk.StateFlags.NORMAL) as number;
                    const gaps = self.get_style_context().get_margin(Gtk.StateFlags.NORMAL).right;
                    const bars = Math.floor((width - gaps) / (barWidth + gaps));
                    if (bars > 0) cava.set_bars(bars);
                });
            }

            self.connect("draw", (_, cr: cairo.Context) => {
                const { width, height } = self.get_allocation();

                if (!cava) {
                    // Show error text if cava unavailable
                    const fg = self.get_style_context().get_color(Gtk.StateFlags.NORMAL);
                    cr.setSourceRGBA(fg.red, fg.green, fg.blue, fg.alpha);
                    const layout = self.create_pango_layout("Visualiser module requires Cava");
                    const [w, h] = layout.get_pixel_size();
                    cr.moveTo((width - w) / 2, (height - h) / 2);
                    cr.setAntialias(cairo.Antialias.BEST);
                    PangoCairo.show_layout(cr, layout);

                    return;
                }

                const bg = self.get_style_context().get_background_color(Gtk.StateFlags.NORMAL);
                cr.setSourceRGBA(bg.red, bg.green, bg.blue, bg.alpha);
                const barWidth = self.get_style_context().get_property("min-width", Gtk.StateFlags.NORMAL) as number;
                const gaps = self.get_style_context().get_margin(Gtk.StateFlags.NORMAL).right;

                const values = cava.get_values();
                const len = values.length - 1;
                const radius = barWidth / 2;
                const xOff = (width - len * (barWidth + gaps) - gaps) / 2 - radius;
                const center = height / 2;
                const half = Math.floor(len / 2);

                // Render channels facing each other
                for (let i = half - 1; i >= 0; i--) {
                    const x = (half - i) * (barWidth + gaps) + xOff;
                    const value = center * values[i];
                    cr.arc(x, center + value, radius, 0, Math.PI);
                    cr.arc(x, center - value, radius, Math.PI, Math.PI * 2);
                    cr.fill();
                }

                for (let i = half; i < len; i++) {
                    const x = (i + 1) * (barWidth + gaps) + xOff;
                    const value = center * values[i];
                    cr.arc(x, center + value, radius, 0, Math.PI);
                    cr.arc(x, center - value, radius, Math.PI, Math.PI * 2);
                    cr.fill();
                }
            });
        }}
    />
);
