# Active power management. One concern, one file: this is the system
# side — the power daemon (power-profiles-daemon by default, or TLP),
# thermald, and the battery charge limit. The profile *switcher* and the
# Waybar *indicator* live home-side (rofi.nix / waybar.nix); they self-
# gate on powerprofilesctl being present, so there's no system→home wiring
# to keep in sync (the same way the Waybar battery widget auto-hides on
# desktops). See the roadmap in README.md.
{ config, lib, ... }:

let
  cfg = config.nomarchy.system.power;
  ppd = cfg.backend == "ppd";
  tlp = cfg.backend == "tlp";
  chargeLimit = cfg.laptop && cfg.batteryChargeLimit != null;
in
{
  config = lib.mkIf cfg.enable {
    # PPD and TLP both drive CPU/platform power — running both fights.
    # `backend` selects exactly one; this assertion only fires if a
    # downstream force-enables the other service directly.
    assertions = [{
      assertion = !(config.services.power-profiles-daemon.enable
        && config.services.tlp.enable);
      message = ''
        nomarchy: power-profiles-daemon and TLP are mutually exclusive.
        Pick one with nomarchy.system.power.backend ("ppd" or "tlp").
      '';
    }];

    # Unprivileged profile switching (the menu/Waybar) goes through
    # polkit, already enabled distro-wide in default.nix.
    services.power-profiles-daemon.enable = lib.mkDefault ppd;
    services.tlp.enable = lib.mkDefault tlp;

    # thermald is Intel-only, so off unless asked (the installer enables
    # it on a GenuineIntel CPU). Sits happily next to either backend.
    services.thermald.enable = lib.mkDefault cfg.thermal.enable;

    # Battery charge limit via sysfs. PPD can't cap charge at all, and
    # TLP's own knob only applies under TLP — so a tiny oneshot writes
    # the threshold directly, independent of the backend. Re-applied on
    # AC state changes by the udev rule below (some firmwares reset the
    # threshold when the charger is unplugged). `[ -w ]` skips paths that
    # don't exist, so this is a clean no-op on hardware without the control.
    systemd.services.nomarchy-battery-charge-limit = lib.mkIf chargeLimit {
      description = "Cap battery charging at ${toString cfg.batteryChargeLimit}%";
      wantedBy = [ "multi-user.target" ];
      serviceConfig = {
        Type = "oneshot";
        RemainAfterExit = true;
      };
      script = ''
        # Name-agnostic (BAT0, CMB0, …): same type/scope filter as
        # nomarchy-battery-notify — BACKLOG #60.
        for d in /sys/class/power_supply/*/; do
          [ "$(cat "$d/type" 2>/dev/null)" = Battery ] || continue
          [ "$(cat "$d/scope" 2>/dev/null || echo System)" = Device ] && continue
          thresh="$d/charge_control_end_threshold"
          [ -w "$thresh" ] && echo ${toString cfg.batteryChargeLimit} > "$thresh"
        done
        exit 0
      '';
    };

    # Re-apply the threshold whenever the mains adapter changes state: the
    # boot oneshot above runs once, but some firmwares clear the limit when
    # the charger is unplugged, so it must be re-asserted on the event.
    # Matched by ATTR{type}=="Mains" (vendor-neutral — the kernel name
    # AC/AC0/ADP1/ACAD varies); --no-block so the RUN+= returns at once
    # (systemd kills long-running udev workers); restart (not try-restart)
    # so it re-applies even if the boot run was inactive.
    services.udev.extraRules = lib.mkIf chargeLimit ''
      SUBSYSTEM=="power_supply", ATTR{type}=="Mains", RUN+="${config.systemd.package}/bin/systemctl --no-block restart nomarchy-battery-charge-limit.service"
    '';
  };
}
