{ config, pkgs, lib, ... }:

let
  jackWrap = drv: pkgs.symlinkJoin {
    name = "${drv.name}-jackwrapped";
    paths = [ drv ];
    buildInputs = [ pkgs.makeWrapper ];
    postBuild = ''
      ls "$out/bin"
      for b in "$out/bin/"*; do
        wrapProgram "$b" \
          --prefix LD_LIBRARY_PATH : "${pkgs.pipewire.jack}/lib"
      done
    '';
  };
  supercolliderPkg =
    if pkgs ? supercollider-with-sc3-plugins then pkgs.supercollider-with-sc3-plugins
    else if pkgs ? supercollider-with-plugins then pkgs.supercollider-with-plugins
    else pkgs.supercollider;

  tidalGhc = pkgs.haskellPackages.ghcWithPackages (hp: with hp; [
    tidal
  ]);

  tidalCmd = pkgs.writeShellApplication {
    name = "tidal";
    runtimeInputs = [ tidalGhc ];
    text = ''
      set -euo pipefail
      mkdir -p "${config.xdg.configHome}/tidal"
      exec ghci -ghci-script "${config.xdg.configHome}/tidal/BootTidal.hs"
    '';
  };

  superdirtSCD = pkgs.writeText "SuperDirt.scd" ''
    s = Server.local;
    s.options.numInputBusChannels = 0;
    s.options.numOutputBusChannels = 2;

    s.waitForBoot {
      SuperDirt.start;
      "SuperDirt started.".postln;
    };
    s.boot;
  '';

  superdirtStart = pkgs.writeShellApplication {
    name = "superdirt-start";
    runtimeInputs = [ supercolliderPkg ];
    text = ''
      set -euo pipefail
      export PIPEWIRE_LATENCY=''${PIPEWIRE_LATENCY:-256/48000}
      exec sclang ${superdirtSCD}
    '';
  };
in
{
  xdg.enable = true;

  home.packages = [
    tidalCmd
    (jackWrap supercolliderPkg)
    (jackWrap superdirtStart)
  ];

  xdg.configFile."tidal/BootTidal.hs".text = ''
    :set -fno-warn-orphans -Wno-type-defaults -XMultiParamTypeClasses -XOverloadedStrings
    :set prompt ""

    -- Import all the boot functions and aliases.
    import Sound.Tidal.Boot
    
    default (Rational, Integer, Double, Pattern String)
    
    -- Create a Tidal Stream with the default settings.
    -- To customize these settings, use 'mkTidalWith' instead
    tidalInst <- mkTidal
    
    -- tidalInst <- mkTidalWith [(superdirtTarget { oLatency = 0.01 }, [superdirtShape])] (defaultConfig {cFrameTimespan = 1/50, cProcessAhead = 1/20})
    
    -- This orphan instance makes the boot aliases work!
    -- It has to go after you define 'tidalInst'.
    instance Tidally where tidal = tidalInst
    
    -- `enableLink` and `disableLink` can be used to toggle synchronisation using the Link protocol.
    -- Uncomment the next line to enable Link on startup.
    -- enableLink
    
    -- You can also add your own aliases in this file. For example:
    -- fastsquizzed pat = fast 2 $ pat # squiz 1.5
    
    :set prompt "tidal> "
    :set prompt-cont ""
  '';
}