# Headless 4K virtual output for Sunshine → Moonlight on a client TV.
#
# NVIDIA proprietary driver: both kernel params are required —
#   video=<connector>:e              force-enables the connector
#   drm.edid_firmware=<connector>:…  loads modes from the EDID blob
#
# Pick a connector that is disconnected on the host (check after boot):
#   grep -H . /sys/class/drm/card*-*/status
#
# Reboot after changing connector or EDID. 4K@60 is realistic on RTX 2070;
# 4K@120 on a sink-less connector needs driver patches (see NVIDIA issue #1184).
{ config, lib, pkgs, ... }:
let
  cfg = config.chiasson.system.streamingDisplay;

  edidFirmware = pkgs.runCommand "sunshine-virtual-4k-edid" {
    nativeBuildInputs = [ pkgs.python3 ];
  } ''
    ${pkgs.python3}/bin/python3 ${./generate-virtual-edid.py} $TMPDIR/${cfg.edidFileName}
    mkdir -p $out/lib/firmware/edid
    cp $TMPDIR/${cfg.edidFileName} $out/lib/firmware/edid/${cfg.edidFileName}
  '';

  # Sunshine 2025.924 wlr capture only accepts a numeric monitor index (not "DP-2").
  # If the index drifts after hotplug, check:
  #   journalctl --user -u sunshine -b | rg 'Monitor [0-9]+ is'
  streamDisplayUp = pkgs.writeShellScriptBin "stream-display-up" ''
    ${pkgs.niri}/bin/niri msg output ${cfg.connector} scale ${toString cfg.niriScale}
    ${pkgs.niri}/bin/niri msg action focus-monitor ${cfg.connector}
    ${pkgs.niri}/bin/niri msg action move-window-to-monitor ${cfg.connector} || true
  '';

  streamDisplayDown = pkgs.writeShellScriptBin "stream-display-down" ''
    ${pkgs.niri}/bin/niri msg action focus-monitor ${cfg.focusMonitorOnEnd}
  '';
in
{
  options.chiasson.system.streamingDisplay = {
    enable = lib.mkEnableOption ''
      Force-enable a spare NVIDIA DRM connector with a 4K EDID for Sunshine/Moonlight.
      Requires reboot. Pair with `chiasson.desktop.niri` output config in `displays.nix`.
    '';

    connector = lib.mkOption {
      type = lib.types.str;
      default = "DP-2";
      example = "HDMI-A-1";
      description = ''
        DRM connector name (e.g. `DP-2`, `HDMI-A-1`). Must be unused on the host —
        14900k desk uses DP-3, DP-4, and HDMI-A-3 by default.
      '';
    };

    edidFileName = lib.mkOption {
      type = lib.types.str;
      default = "virtual-4k.bin";
      description = "Filename under `/lib/firmware/edid/` referenced by `drm.edid_firmware`.";
    };

    mode = lib.mkOption {
      type = lib.types.str;
      default = "3840x2160@60";
      description = "Mode Niri should use on the virtual output (must match EDID).";
    };

    niriPosition = lib.mkOption {
      type = lib.types.str;
      default = "x=7680 y=0";
      description = ''
        Niri `position` for the virtual panel — keep it clear of desk monitors
        so streamed windows do not overlap your ultrawide layout.
      '';
    };

    niriScale = lib.mkOption {
      type = lib.types.float;
      default = 1.5;
      example = 1.5;
      description = ''
        Niri `scale` on the virtual panel. Values above 1.0 enlarge UI and text
        on the 4K framebuffer (helpful when viewing on a TV from the couch).
      '';
    };

    focusMonitorOnEnd = lib.mkOption {
      type = lib.types.str;
      default = "DP-3";
      description = "Niri monitor to refocus when a Moonlight session ends.";
    };

    sunshineOutputIndex = lib.mkOption {
      type = lib.types.str;
      default = "3";
      example = "3";
      description = ''
        Wayland/wlr monitor index for Sunshine `output_name`. Sunshine 2025.924 ignores
        connector strings like `DP-2` and falls back to monitor 0 (your primary).
        Find the index with:
        `journalctl --user -u sunshine -b | rg "Monitor [0-9]+ is ${cfg.connector}"`
      '';
    };
  };

  config = lib.mkIf cfg.enable (lib.mkMerge [
    {
      hardware.firmware = [ edidFirmware ];

      boot.kernelParams = [
        "video=${cfg.connector}:e"
        "drm.edid_firmware=${cfg.connector}:edid/${cfg.edidFileName}"
      ];

      environment.systemPackages = [
        streamDisplayUp
        streamDisplayDown
      ];
    }
    (lib.mkIf config.chiasson.system.gaming.sunshine.enable {
      services.sunshine.settings = {
        capture = "wlr";
        output_name = cfg.sunshineOutputIndex;
        global_prep_cmd = "[{\"do\":\"${streamDisplayUp}/bin/stream-display-up\",\"undo\":\"${streamDisplayDown}/bin/stream-display-down\"}]";
      };
    })
  ]);
}
