# Installable Psysonic (Tauri): npm build → cargo tauri build --no-bundle.
# Source: `self` (this repo). Package version is read from package.json.
# `npmDepsHash` in nix/upstream-sources.json is refreshed by the release
# workflow (see .github/workflows/release.yml, verify-nix job).

{
  lib,
  stdenv,
  fetchNpmDeps,
  npmHooks,
  rustPlatform,
  cargo,
  rustc,
  pkg-config,
  cmake,
  openssl,
  gtk3,
  webkitgtk_4_1,
  libsoup_3,
  glib-networking,
  alsa-lib,
  libayatana-appindicator,
  atk,
  cairo,
  gdk-pixbuf,
  glib,
  pango,
  librsvg,
  cargo-tauri,
  nodejs,
  makeWrapper,
  wrapGAppsHook4,
  copyDesktopItems,
  makeDesktopItem,
  gst_all_1,
  src,
  upstreamMeta,
  # When true, wrapProgram sets GDK_BACKEND=x11 (legacy conservative stack).
  # When false (default), only lib paths — GDK follows session; binary applies webkit2gtk-nvidia-quirk only.
  forceGdkX11 ? false,
}:

let
  version = (lib.importJSON (src + "/package.json")).version;
  # WebKit media stack needs discoverable GStreamer plugins (e.g. appsink in gst-plugins-base).
  gstPlugins = with gst_all_1; [
    gstreamer
    gst-plugins-base
    gst-plugins-good
    gst-plugins-bad
  ];
  gstPluginPath = lib.makeSearchPath "lib/gstreamer-1.0" gstPlugins;
  srcClean = lib.cleanSourceWith {
    inherit src;
    filter =
      path: _:
      let
        f = toString path;
      in
      !(lib.hasInfix "/node_modules/" f)
      && !(lib.hasInfix "/dist/" f)
      && !(lib.hasInfix "/target/" f)
      && !(lib.hasInfix "/.git/" f)
      && !(lib.hasInfix "/result/" f)
      && !(lib.hasInfix "/.flatpak-builder/" f)
      && !(lib.hasInfix "/.build-local/" f);
  };
  npmDeps = fetchNpmDeps {
    src = srcClean;
    hash = upstreamMeta.npmDepsHash;
  };
  cargoLockFile = src + "/src-tauri/Cargo.lock";
in

stdenv.mkDerivation (finalAttrs: {
  pname = "psysonic";
  inherit version;
  src = srcClean;
  inherit npmDeps;

  strictDeps = true;

  # cmake is only for Rust deps (e.g. libopus); no top-level CMakeLists.txt in repo root
  dontUseCmakeConfigure = true;

  nativeBuildInputs = [
    npmHooks.npmConfigHook
    cargo
    rustc
    rustPlatform.cargoSetupHook
    pkg-config
    cmake
    makeWrapper
    wrapGAppsHook4
    copyDesktopItems
    cargo-tauri
    nodejs
  ];

  buildInputs = [
    gtk3
    webkitgtk_4_1
    libsoup_3
    glib-networking
    openssl
    alsa-lib
    libayatana-appindicator
    atk
    cairo
    gdk-pixbuf
    glib
    pango
    librsvg
  ]
  ++ gstPlugins;

  cargoRoot = "src-tauri";
  cargoDeps = rustPlatform.importCargoLock {
    lockFile = cargoLockFile;
    # Local path overrides for `[patch.crates-io]` entries in src-tauri/Cargo.toml.
    # Keep in sync with that block — importCargoLock needs the source to match
    # the lockfile entries for patched crates (otherwise it tries to fetch from
    # crates.io and the hash mismatches).
    outputHashes = { };
  };

  dontUseCargoParallelJobs = true;

  env = {
    OPENSSL_DIR = "${openssl.dev}";
    OPENSSL_LIB_DIR = "${openssl.out}/lib";
    OPENSSL_INCLUDE_DIR = "${openssl.dev}/include";
    VITE_LASTFM_API_KEY = "";
    VITE_LASTFM_API_SECRET = "";
  };

  # beforeBuildCommand runs npm run build; npmConfigHook supplies offline node_modules
  buildPhase = ''
    runHook preBuild
    export HOME=$(mktemp -d)
    (cd src-tauri && cargo tauri build --no-bundle)
    runHook postBuild
  '';

  installPhase = ''
    runHook preInstall
    install -Dm755 src-tauri/target/release/psysonic -t $out/bin
    install -Dm644 src-tauri/icons/128x128.png $out/share/icons/hicolor/128x128/apps/psysonic.png
    runHook postInstall
  '';

  desktopItems = [
    (makeDesktopItem {
      name = "psysonic";
      desktopName = "Psysonic";
      comment = "Subsonic-compatible music player";
      icon = "psysonic";
      exec = "psysonic";
      categories = [ "AudioVideo" "Audio" "Player" ];
    })
  ];

  postFixup =
    let
      gdkX11Wrap = lib.optionalString forceGdkX11 ''
        --set GDK_BACKEND x11
      '';
    in
    ''
      wrapProgram $out/bin/psysonic \
        --prefix LD_LIBRARY_PATH : "${lib.makeLibraryPath [ libayatana-appindicator ]}" \
        --prefix GST_PLUGIN_PATH : "${gstPluginPath}" \
        --prefix GIO_EXTRA_MODULES : "${glib-networking}/lib/gio/modules" \
        ${gdkX11Wrap}
    '';

  meta = {
    description = "Desktop music player for Subsonic-compatible servers";
    homepage = "https://github.com/Psychotoxical/psysonic";
    license = lib.licenses.gpl3Only;
    mainProgram = "psysonic";
    platforms = lib.platforms.linux;
  };
})
