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

{
  imports = [
    ./hardware-configuration.nix
  ];

  c3d2 = {
    hq.interface = "eth0";
    hq.statistics.enable = true;
    k-ot.enable = true;
    audioServer.enable = true;
  };

  boot = {
    growPartition = true;
    kernelParams = [ "console=tty0" ];
    loader.grub.enable = false;
    loader.efi.canTouchEfiVariables = true;
    supportedFilesystems = lib.mkForce [ "vfat" "ext4" ];
    tmpOnTmpfs = true;
  };

  hardware = {
    bluetooth.enable = true;
    deviceTree.enable = true;
  };

  nix.settings = {
    cores = 2;
    max-jobs = 1;
  };

  nixpkgs.config.packageOverrides = pkgs: {
    makeModulesClosure = x:
      # prevent kernel install fail due to missing modules
      pkgs.makeModulesClosure (x // { allowMissing = true; });
  };

  nixpkgs.overlays = [
    (final: prev: {
      python3 = prev.python3.override {
        packageOverrides = python-final: python-prev: {
          aiohttp = python-prev.aiohttp.overrideAttrs ({ nativeBuildInputs ? [],... }: {
            nativeBuildInputs = nativeBuildInputs ++ [python-final.setuptools];

            doCheck = false;
            doInstallCheck = false;
          });

          pystray = python-prev.pystray.overrideAttrs (_: {
            doCheck = false;
            doInstallCheck = false;
          });

          samplerate = python-prev.samplerate.overrideAttrs (_: {
            dontUseSetuptoolsCheck = true;
          });
        };
      };
      python3Packages = final.python3.pkgs;
    })
  ];

  networking = {
    domain = "hq.c3d2.de";
    firewall = {
      allowedTCPPorts = [
        80 # ledfx
        4713 # pulseaudio/pipewire network sync
        5355 # llmnr
      ];
      allowedUDPPorts = [
        5353 # mdns
        5355 # llmnr
      ];
    };
    hostName = "pulsebert";
    useDHCP = false;
    interfaces.eth0.useDHCP = true;
  };

  environment.systemPackages = with pkgs; [
    mpd
    mpv
    ncmpcpp
    ncpamixer
    pulseaudio # required for pactl
  ];

  # https://github.com/dump-dvb/nix-config/blob/310ceedca5ab2d5c22070bd73c603926b6100a74/hardware/configuration-rpi-3b.nix#L16
  sdImage = lib.mkForce {
    populateFirmwareCommands =
      let
        configTxt = pkgs.writeText "config.txt" ''
          [pi3]
          kernel=u-boot-rpi3.bin
          hdmi_force_hotplug=1
          [pi02]
          kernel=u-boot-rpi3.bin
          [pi4]
          kernel=u-boot-rpi4.bin
          enable_gic=1
          armstub=armstub8-gic.bin
          # Otherwise the resolution will be weird in most cases, compared to
          # what the pi3 firmware does by default.
          disable_overscan=1
          # Supported in newer board revisions
          arm_boost=1
          [cm4]
          # Enable host mode on the 2711 built-in XHCI USB controller.
          # This line should be removed if the legacy DWC2 controller is required
          # (e.g. for USB device mode) or if USB support is not required.
          otg_mode=1
          [all]
          # Boot in 64-bit mode.
          arm_64bit=1
          # U-Boot needs this to work, regardless of whether UART is actually used or not.
          # Look in arch/arm/mach-bcm283x/Kconfig in the U-Boot tree to see if this is still
          # a requirement in the future.
          enable_uart=1
          # Prevent the firmware from smashing the framebuffer setup done by the mainline kernel
          # when attempting to show low-voltage or overtemperature warnings.
          avoid_warnings=1
        '';
      in
      ''
        (cd ${pkgs.raspberrypifw}/share/raspberrypi/boot && cp bootcode.bin fixup*.dat start*.elf $NIX_BUILD_TOP/firmware/)
        # Add the config
        cp ${configTxt} firmware/config.txt
        # Add pi3 specific files
        cp ${pkgs.ubootRaspberryPi3_64bit}/u-boot.bin firmware/u-boot-rpi3.bin
        # Add pi4 specific files
        cp ${pkgs.ubootRaspberryPi4_64bit}/u-boot.bin firmware/u-boot-rpi4.bin
        cp ${pkgs.raspberrypi-armstubs}/armstub8-gic.bin firmware/armstub8-gic.bin
        cp ${pkgs.raspberrypifw}/share/raspberrypi/boot/bcm2711-rpi-4-b.dtb firmware/
        cp ${pkgs.raspberrypifw}/share/raspberrypi/boot/bcm2711-rpi-400.dtb firmware/
        cp ${pkgs.raspberrypifw}/share/raspberrypi/boot/bcm2711-rpi-cm4.dtb firmware/
        cp ${pkgs.raspberrypifw}/share/raspberrypi/boot/bcm2711-rpi-cm4s.dtb firmware/
      '';
    populateRootCommands = ''
      mkdir -p ./files/boot
      ${config.boot.loader.generic-extlinux-compatible.populateCmd} -c ${config.system.build.toplevel} -d ./files/boot
    '';
  };

  security = {
    rtkit.enable = true;
    sudo = {
      enable = true;
      wheelNeedsPassword = false;
    };
  };

  services = {
    avahi.nssmdns = true;
    # Do not log to flash but also breaks journalctl --user
    # journald.extraConfig = ''
    #   Storage=volatile
    # '';

    openssh = {
      enable = true;
    };

    nginx = {
      enable = true;
      virtualHosts = {
        "drkkr.hq.c3d2.de" = {
          default = true;
          enableACME = true;
          forceSSL = true;
          locations."/" = {
            proxyPass = "http://127.0.0.1:${toString config.services.octoprint.port}";
            proxyWebsockets = true;
            extraConfig = ''
              proxy_set_header X-Scheme $scheme;
              proxy_set_header Accept-Encoding identity;
              client_max_body_size 200M;
            '';
          };
          # locations."/cam/stream" = {
          #   proxyPass = "http://localhost:3020/?action=stream";
          #   extraConfig = "proxy_pass_request_headers off;";
          # };
          # locations."/cam/capture" = {
          #   proxyPass = "http://localhost:3020/?action=snapshot";
          #   extraConfig = "proxy_pass_request_headers off;";
          # };
        };
        "drucker.hq.c3d2.de" = {
          enableACME = true;
          forceSSL = true;
          locations."/".return = "307 https://drkkr.hq.c3d2.de/";
        };
        "pulsebert.hq.c3d2.de" = {
          enableACME = true;
          forceSSL = true;
          locations."/" = {
            proxyPass = "http://127.0.0.1:8888";
            proxyWebsockets = true;
          };
        };
      };
    };

    octoprint = {
      enable = true;
      port = 8080;
      # extraConfig.webcam = {
      #   snapshot = "http://localhost:3020?action=snapshot";
      #   stream = "https://drkkr.hq.c3d2.de/cam/stream";
      # };
    };
  };

  system.stateVersion = "22.11";

  systemd.user.services.ledfx = {
    after = [ "pipewire.target" ];
    wantedBy = [ "default.target" ];
    serviceConfig = {
      ExecStart = "${pkgs.ledfx}/bin/ledfx";
    };
  };

  users.users = lib.optionalAttrs config.services.octoprint.enable {
    # Allow access to printer serial port and GPIO
    "${config.services.octoprint.user}".extraGroups = [ "dialout" ];
  };
}
