{ lib
, fetchFromGitHub
, fetchpatch
, rustPlatform
, makeWrapper
, pkg-config
, perl
, openssl
, rust-jemalloc-sys
, python3
, wrapQtAppsHook
, qtbase
, qtsvg
, xdg-utils
, substituteAll
, buildNpmPackage
}:

let
  version = "0.12.2";
  sources = fetchFromGitHub {
    owner = "ActivityWatch";
    repo = "activitywatch";
    rev = "v${version}";
    sha256 = "sha256-IvRXfxTOSgBVlxy4SVij+POr7KgvXTEjGN3lSozhHkY=";
    fetchSubmodules = true;
  };
in
rec {
  aw-watcher-afk = python3.pkgs.buildPythonApplication {
    pname = "aw-watcher-afk";
    inherit version;

    format = "pyproject";

    src = "${sources}/aw-watcher-afk";

    nativeBuildInputs = [
      python3.pkgs.poetry-core
    ];

    propagatedBuildInputs = with python3.pkgs; [
      aw-client
      xlib
      pynput
    ];

    pythonImportsCheck = [ "aw_watcher_afk" ];

    meta = with lib; {
      description = "Watches keyboard and mouse activity to determine if you are AFK or not (for use with ActivityWatch)";
      homepage = "https://github.com/ActivityWatch/aw-watcher-afk";
      maintainers = with maintainers; [ huantian ];
      license = licenses.mpl20;
    };
  };

  aw-watcher-window = python3.pkgs.buildPythonApplication {
    pname = "aw-watcher-window";
    inherit version;

    format = "pyproject";

    src = "${sources}/aw-watcher-window";

    nativeBuildInputs = [
      python3.pkgs.poetry-core
    ];

    propagatedBuildInputs = with python3.pkgs; [
      aw-client
      xlib
    ];

    pythonImportsCheck = [ "aw_watcher_window" ];

    meta = with lib; {
      description = "Cross-platform window watcher (for use with ActivityWatch)";
      homepage = "https://github.com/ActivityWatch/aw-watcher-window";
      maintainers = with maintainers; [ huantian ];
      license = licenses.mpl20;
    };
  };

  aw-qt = python3.pkgs.buildPythonApplication {
    pname = "aw-qt";
    inherit version;

    format = "pyproject";

    src = "${sources}/aw-qt";

    nativeBuildInputs = [
      python3.pkgs.poetry-core
      wrapQtAppsHook
    ];

    propagatedBuildInputs = with python3.pkgs; [
      aw-core
      qtbase
      qtsvg # Rendering icons in the trayicon menu
      pyqt6
      click
    ];

    # Prevent double wrapping
    dontWrapQtApps = true;

    makeWrapperArgs = [
      "--suffix PATH : ${lib.makeBinPath [ xdg-utils ]}"
    ];

    postPatch = ''
      sed -E 's#PyQt6 = "6.3.1"#PyQt6 = "^6.4.0"#g' -i pyproject.toml
    '';

    postInstall = ''
      install -D resources/aw-qt.desktop $out/share/applications/aw-qt.desktop

      # For the actual tray icon, see
      # https://github.com/ActivityWatch/aw-qt/blob/8ec5db941ede0923bfe26631acf241a4a5353108/aw_qt/trayicon.py#L211-L218
      install -D media/logo/logo.png $out/${python3.sitePackages}/media/logo/logo.png

      # For .desktop file and your desktop environment
      install -D media/logo/logo.svg $out/share/icons/hicolor/scalable/apps/activitywatch.svg
      install -D media/logo/logo.png $out/share/icons/hicolor/512x512/apps/activitywatch.png
      install -D media/logo/logo-128.png $out/share/icons/hicolor/128x128/apps/activitywatch.png
    '';

    preFixup = ''
      makeWrapperArgs+=(
        "''${qtWrapperArgs[@]}"
      )
    '';

    pythonImportsCheck = [ "aw_qt" ];

    meta = with lib; {
      description = "Tray icon that manages ActivityWatch processes, built with Qt";
      homepage = "https://github.com/ActivityWatch/aw-qt";
      maintainers = with maintainers; [ huantian ];
      license = licenses.mpl20;
    };
  };

  aw-server-rust = rustPlatform.buildRustPackage {
    pname = "aw-server-rust";
    inherit version;

    src = "${sources}/aw-server-rust";

    cargoLock = {
      lockFile = ./Cargo.lock;
      outputHashes = {
        "rocket_cors-0.6.0-alpha1" = "sha256-GuMekgnsyuOg6lMiVvi4TwMba4sAFJ/zkgrdzSeBrv0=";
      };
    };

    # Bypass rust nightly features not being available on rust stable
    RUSTC_BOOTSTRAP = 1;

    patches = [
      # Override version string with hardcoded value as it may be outdated upstream.
      (substituteAll {
        src = ./override-version.patch;
        version = sources.rev;
      })

      # Can be removed with release 0.12.3
      (fetchpatch {
        name = "remove-unused-unstable-features.patch";
        url = "https://github.com/ActivityWatch/aw-server-rust/commit/e1cd761d2f0a9309eb851b59732c2567a7ae2d3a.patch";
        hash = "sha256-wP+3XZDkr148XY5b8RV3obuLczAFBE3FhaYPqnmmGcU=";
        includes = [ "aw-server/src/lib.rs" ];
      })
    ];

    nativeBuildInputs = [
      makeWrapper
      pkg-config
      perl
    ];

    buildInputs = [
      openssl
      rust-jemalloc-sys
    ];

    postFixup = ''
      wrapProgram "$out/bin/aw-server" \
        --prefix XDG_DATA_DIRS : "$out/share"

      mkdir -p "$out/share/aw-server"
      ln -s "${aw-webui}" "$out/share/aw-server/static"
    '';

    preCheck = ''
      # Fake home folder for tests that use ~/.cache and ~/.local/share
      export HOME="$TMPDIR"
    '';

    meta = with lib; {
      description = "High-performance implementation of the ActivityWatch server, written in Rust";
      homepage = "https://github.com/ActivityWatch/aw-server-rust";
      maintainers = with maintainers; [ huantian ];
      mainProgram = "aw-server";
      platforms = platforms.linux;
      license = licenses.mpl20;
    };
  };

  aw-webui = buildNpmPackage {
    pname = "aw-webui";
    inherit version;

    src = "${sources}/aw-server-rust/aw-webui";

    npmDepsHash = "sha256-yds2P2PKfTB6yUGnc+P73InV5+MZP9kmz2ZS4CRqlmA=";

    patches = [
      # Hardcode version to avoid the need to have the Git repo available at build time.
      (substituteAll {
        src = ./commit-hash.patch;
        commit_hash = sources.rev;
      })
    ];

    installPhase = ''
      runHook preInstall
      mv dist $out
      cp media/logo/logo.{png,svg} $out/static/
      runHook postInstall
    '';

    doCheck = true;
    checkPhase = ''
      runHook preCheck
      npm test
      runHook postCheck
    '';

    meta = with lib; {
      description = "Web-based UI for ActivityWatch, built with Vue.js";
      homepage = "https://github.com/ActivityWatch/aw-webui/";
      maintainers = with maintainers; [ huantian ];
      license = licenses.mpl20;
    };
  };
}
