import { Astal, Gtk, Gdk } from "astal/gtk4";
import { Variable, GLib, bind, execAsync, exec } from "astal";
import Battery from "gi://AstalBattery";
import Bluetooth from "gi://AstalBluetooth";
import Wp from "gi://AstalWp";
import Network from "gi://AstalNetwork";
import Hyprland from "gi://AstalHyprland";
import Brightness from "../service/brightness";

const network = Network.get_default();
const wifi = bind(network, "wifi");
const hypr = Hyprland.get_default();
const bluetooth = Bluetooth.get_default();

function Wifi() {
  return (
    <box visible={wifi.as(Boolean)}>
      {wifi.as(
        (wifi) =>
          wifi && (
            <image cssClasses={["Wifi"]} iconName={bind(wifi, "iconName")} />
          ),
      )}
    </box>
  );
}

function Audio() {
  const speaker = Wp.get_default()?.audio.defaultSpeaker!;

  return (
    <box cssClasses={["Audio"]}>
      <image iconName={bind(speaker, "volumeIcon")} />
    </box>
  );
}

function AudioSlider() {
  const speaker = Wp.get_default()?.audio.defaultSpeaker!;

  return (
    <box cssClasses={["AudioSlider"]}>
      <image iconName={bind(speaker, "volumeIcon")} />
      <slider
        hexpand
        widthRequest={100}
        onChangeValue={({ value }) => {
          speaker.volume = value;
        }}
        value={bind(speaker, "volume")}
      />
    </box>
  );
}

function BrightnessSlider() {
  const brightness = Brightness.get_default();

  return (
    <box cssClasses={["BrightnessSlider"]}>
      <image iconName={"display-brightness-symbolic"} />
      <slider
        hexpand
        widthRequest={100}
        onChangeValue={({ value }) => {
          brightness.screen = value;
        }}
        value={bind(brightness, "screen")}
      />
    </box>
  );
}

function BatteryLevel() {
  const bat = Battery.get_default();

  return (
    <box cssClasses={["Battery"]} visible={bind(bat, "isPresent")}>
      <image iconName={bind(bat, "batteryIconName")} />
      <label
        label={bind(bat, "percentage").as((p) => `${Math.floor(p * 100)} %`)}
      />
    </box>
  );
}

function Time({ format = "%H:%M - %A %e." }) {
  const time = Variable<string>("").poll(
    1000,
    () => GLib.DateTime.new_now_local().format(format)!,
  );

  return (
    <box cssClasses={["Time"]}>
      <menubutton>
        <label label={time()} />
        <popover hasArrow={false}>
          <Gtk.Calendar />
        </popover>
      </menubutton>
    </box>
  );
}

function IdleInhibitor() {
  const icon = Variable(getIcon());

  function getIcon() {
    const state = exec("matcha --status");
    const enabled = state.match(/on/g);
    return enabled ? "my-caffeine-on-symbolic" : "my-caffeine-off-symbolic";
  }

  function toggle() {
    exec("matcha --toggle");
    icon.set(getIcon());
  }

  return (
    <box cssName="IdleInhibitor">
      <button
        onClicked={() => toggle()}
        iconName={bind(icon).as((iconName) => iconName)}
      />
    </box>
  );
}
function QuickSettings() {
  return (
    <box cssClasses={["QuickSettings"]}>
      <menubutton>
        <box>
          <Audio />
          <Wifi />
          <BatteryLevel />
        </box>
        <popover hasArrow={false}>
          <box vertical>
            <box
              cssClasses={["Toggles"]}
              spacing={30}
              halign={Gtk.Align.CENTER}
              hexpand
            >
              <box visible={wifi.as(Boolean)} cssClasses={["WifiButton"]}>
                {wifi.as(
                  (wifi) =>
                    wifi && (
                      <button
                        onClicked={() => (wifi.enabled = !wifi.enabled)}
                        iconName={bind(wifi, "iconName")}
                      />
                    ),
                )}
              </box>
              <box
                visible={bluetooth.adapter != null}
                halign={Gtk.Align.CENTER}
              >
                <button
                  onClicked={() => bluetooth.toggle()}
                  iconName={bind(bluetooth, "is_powered").as((p) =>
                    p ? "bluetooth-symbolic" : "bluetooth-disabled-symbolic",
                  )}
                />
              </box>
              <IdleInhibitor />
            </box>
            <box vertical>
              <AudioSlider />
              <BrightnessSlider />
            </box>
          </box>
        </popover>
      </menubutton>
    </box>
  );
}

function Workspaces() {
  return (
    <box cssClasses={["Workspaces"]}>
      {bind(hypr, "workspaces").as((wss) =>
        wss
          .filter((ws) => !(ws.id >= -99 && ws.id <= -2)) // filter out special workspaces
          .sort((a, b) => a.id - b.id)
          .map((ws) => (
            <button
              valign={Gtk.Align.CENTER}
              cssClasses={bind(hypr, "focusedWorkspace").as((fw) =>
                ws === fw ? ["focused"] : [""],
              )}
              onClicked={() => ws.focus()}
            ></button>
          )),
      )}
    </box>
  );
}
export default function Bar(monitor: Gdk.Monitor) {
  const { TOP, LEFT, RIGHT } = Astal.WindowAnchor;

  return (
    <window
      visible
      namespace={"bar"}
      cssClasses={["Bar"]}
      gdkmonitor={monitor}
      exclusivity={Astal.Exclusivity.EXCLUSIVE}
      anchor={TOP | LEFT | RIGHT}
    >
      <centerbox shrinkCenterLast>
        <box hexpand halign={Gtk.Align.START}>
          <Workspaces />
        </box>
        <box halign={Gtk.Align.CENTER}>
          <Time />
        </box>
        <box halign={Gtk.Align.END}>
          <QuickSettings />
        </box>
      </centerbox>
    </window>
  );
}
