import { bind } from "astal";
import { Gtk } from "astal/gtk4";
import AstalWp from "gi://AstalWp";

const wp = AstalWp.get_default()!;

const AudioModule = () => {
    const setVolumeSpeaker = (volume: number) => {
        wp.defaultSpeaker.set_volume(volume / 100);
    };

    const setVolumeMicrophone = (volume: number) => {
        wp.defaultMicrophone.set_volume(volume / 100);
    };

    const speakerSelector = SinkSelectPopover(AstalWp.MediaClass.AUDIO_SPEAKER);
    const micSelector = SinkSelectPopover(AstalWp.MediaClass.AUDIO_MICROPHONE);

    return (
        <box cssClasses={["audio-box"]} vertical>
            <box hexpand vexpand>
                <button
                    onClicked={() =>
                        wp.defaultSpeaker.set_mute(
                            !wp.defaultSpeaker.get_mute(),
                        )
                    }
                    tooltipText={"Mute audio output"}
                    child={
                        <image
                            iconName={bind(wp.defaultSpeaker, "volumeIcon")}
                            marginEnd={3}
                        ></image>
                    }
                ></button>
                <label
                    label={bind(wp.defaultSpeaker, "volume").as(
                        v => Math.round(100 * v) + "%",
                    )}
                ></label>
                <slider
                    value={bind(wp.defaultSpeaker, "volume").as(v => 100 * v)}
                    max={100}
                    min={0}
                    step={1}
                    hexpand
                    vexpand
                    onChangeValue={self => setVolumeSpeaker(self.value)}
                ></slider>
                <button
                    cssClasses={["sink-select-button"]}
                    tooltipText={"Pick audio output"}
                    child={
                        <box>
                            <image iconName={"speaker-symbolic"}></image>
                            {speakerSelector}
                        </box>
                    }
                    onClicked={() => speakerSelector.popup()}
                ></button>
            </box>
            <box hexpand vexpand>
                <button
                    onClicked={() =>
                        wp.defaultMicrophone.set_mute(
                            !wp.defaultMicrophone.get_mute(),
                        )
                    }
                    tooltipText={"Mute audio input"}
                    child={
                        <image
                            iconName={bind(wp.defaultMicrophone, "volumeIcon")}
                            marginEnd={3}
                        ></image>
                    }
                ></button>
                <label
                    label={bind(wp.defaultMicrophone, "volume").as(
                        v => Math.round(100 * v) + "%",
                    )}
                ></label>
                <slider
                    value={bind(wp.defaultMicrophone, "volume").as(
                        v => 100 * v,
                    )}
                    max={100}
                    min={0}
                    step={1}
                    hexpand
                    vexpand
                    onChangeValue={self => setVolumeMicrophone(self.value)}
                ></slider>
                <button
                    cssClasses={["sink-select-button"]}
                    tooltipText={"Select audio input"}
                    child={
                        <box>
                            <image iconName={"microphone"}></image>
                            {micSelector}
                        </box>
                    }
                    onClicked={() => micSelector.popup()}
                ></button>
            </box>
        </box>
    );
};

const SinkPicker = (type: AstalWp.MediaClass) => {
    const devices = bind(wp, "nodes");

    return (
        <box vertical>
            <label
                label={`Available Audio ${type === AstalWp.MediaClass.AUDIO_SPEAKER ? "Output" : type === AstalWp.MediaClass.AUDIO_MICROPHONE ? "Input" : ""} Devices`}
                cssClasses={[ 'title-2' ]}
            ></label>
            <Gtk.Separator marginBottom={5} marginTop={3}></Gtk.Separator>
            <box vertical cssClasses={["sink-picker"]}>
                {devices.as(d => {
                    return d.map(device => {
                        if (device.get_media_class() !== type) {
                            return <box cssClasses={[ 'empty' ]}></box>;
                        }
                        return (
                            <button
                                cssClasses={bind(device, "id").as(id => {
                                    if (
                                        id ===
                                        (type ===
                                        AstalWp.MediaClass.AUDIO_SPEAKER
                                            ? wp.defaultSpeaker.id
                                            : type ===
                                                AstalWp.MediaClass
                                                    .AUDIO_MICROPHONE
                                              ? wp.defaultMicrophone.id
                                              : "")
                                    ) {
                                        return [
                                            "sink-option",
                                            "currently-selected-sink-option",
                                        ];
                                    } else {
                                        return ["sink-option"];
                                    }
                                })}
                                child={
                                    <box halign={Gtk.Align.START}>
                                        <image
                                            iconName={bind(device, "icon").as(
                                                icon => icon,
                                            )}
                                            marginEnd={3}
                                        ></image>
                                        <label
                                            label={bind(
                                                device,
                                                "description",
                                            ).as(t => t ?? "")}
                                        ></label>
                                    </box>
                                }
                                onClicked={() => {
                                    device.set_is_default(true);
                                }}
                            ></button>
                        );
                    });
                })}
            </box>
        </box>
    );
};

const SinkSelectPopover = (type: AstalWp.MediaClass) => {
    const popover = new Gtk.Popover();

    popover.set_child(SinkPicker(type));

    return popover;
};

export default {
    AudioModule,
};
