# Night light — a scheduled blue-light filter via hyprsunset (Hyprland's own
# gamma/temperature tool). Warm at night, identity (no shift) by day; the
# schedule (temperature/sunrise/sunset) is tuned via nomarchy.nightlight.* in
# home.nix and baked into the unit's time-based `profile`.
#
# Off by default and opt-in. Two git-tracked flags in the state file, both
# menu-written (no ~/.local/state):
#   settings.nightlight.installed — does the hyprsunset unit exist? Sticky; the
#     option mkDefault-reads it, so the FIRST enable from the menu rebuilds (to
#     create the unit) and an instant-off is never undone by a later rebuild.
#   settings.nightlight.on — runtime on/off. Toggled INSTANTLY (write + systemctl,
#     no rebuild); read by the unit's ExecCondition (should-start) at session
#     start so the choice survives logout/reboot via the *live* state, not the
#     eval-frozen store copy. A later rebuild bakes the same value (no divergence).
{ config, lib, pkgs, ... }:

let
  cfg = config.nomarchy.nightlight;
  s = config.nomarchy.settings.nightlight;
  sync = lib.getExe config.nomarchy.package;
  # Runtime-on default for when the `on` key hasn't been written yet (e.g. right
  # after the first enable). Baked at eval; only used when the live key is absent.
  onDefault = lib.boolToString s.on;

  nomarchy-nightlight = pkgs.writeShellScriptBin "nomarchy-nightlight" ''
    unit=hyprsunset.service
    # Instant runtime on/off: write the in-flake state WITHOUT a rebuild.
    write_on() { ${sync} --quiet set settings.nightlight.on "$1" --no-switch; }
    # First enable: mark the feature installed and REBUILD to create the unit
    # (the one rebuild we accept; every toggle after is instant).
    install_feature() { ${sync} --quiet set settings.nightlight.installed true; }
    # Read the LIVE working-tree on/off (~/.nomarchy via $NOMARCHY_PATH), not the
    # store copy baked into this generation; fall back to the eval-time default
    # when absent. Normalise Python's True/False bool rendering.
    is_on() {
      v=$(${sync} get settings.nightlight.on 2>/dev/null) || v=${onDefault}
      case "$v" in true|True) return 0 ;; *) return 1 ;; esac
    }
    installed() { systemctl --user cat "$unit" >/dev/null 2>&1; }
    start() { systemctl --user start "$unit" 2>/dev/null || true; }
    stop()  { systemctl --user stop  "$unit" 2>/dev/null || true; }
    case "''${1:-toggle}" in
      should-start) is_on ;;                       # ExecCondition gate (login/reboot)
      status)
        # Waybar (polls every 3s): moon while running; print nothing otherwise so
        # the module self-hides — enable / re-enable from the System menu.
        systemctl --user is-active --quiet "$unit" \
          && printf '{"text":"󰖔","tooltip":"Night light on — warm on schedule (click to disable)","class":"on"}\n'
        exit 0 ;;
      on)
        if installed; then write_on true; start; else install_feature; start; fi ;;
      off) write_on false; stop ;;
      toggle)
        if systemctl --user is-active --quiet "$unit"; then
          write_on false; stop                     # on -> off (instant)
        elif installed; then
          write_on true; start                     # installed, off -> on (instant)
        else
          install_feature; start                   # first enable (rebuilds)
        fi ;;
      *) echo "usage: nomarchy-nightlight [toggle|status|on|off|should-start]" >&2; exit 64 ;;
    esac
  '';
in
{
  config = {
    # Unit presence tracks the sticky `installed` flag the menu writes (first
    # enable rebuilds). mkDefault so a hand-set nomarchy.nightlight.enable in
    # home.nix also works as a declarative opt-in.
    nomarchy.nightlight.enable = lib.mkDefault s.installed;

    services.hyprsunset = lib.mkIf cfg.enable {
      enable = true;
      settings.profile = [
        # Daytime: identity = no colour change.
        { time = cfg.sunrise; identity = true; }
        # Night: shift to the warm temperature.
        { time = cfg.sunset; temperature = cfg.temperature; }
      ];
    };

    # Gate the unit on the LIVE on/off state at start time (login/reboot), not
    # at eval time — so a menu toggle (written without a rebuild) is honoured on
    # the next session. A failed condition skips the unit (inactive, not failed).
    systemd.user.services.hyprsunset.Service.ExecCondition =
      lib.mkIf cfg.enable "${nomarchy-nightlight}/bin/nomarchy-nightlight should-start";

    home.packages = [ nomarchy-nightlight ];
  };
}
