{ config, pkgs, lib, ... }:
with lib;
let
  cfg = config.nas-apps.actual;
  settings = import ../settings.nix;
  dataDir = "/data";
  hostAddress = settings.hostAddress;
  actualUserId = config.users.users.nix-apps.uid;
  actualGroupId = config.users.groups.jallen-nas.gid;
in
{
  imports = [ ./options.nix ];

  config = mkIf cfg.enable {
    containers.actual = {
      autoStart = true;
      privateNetwork = true;
      hostAddress = hostAddress;
      localAddress = cfg.localAddress;

      bindMounts = {
        ${dataDir} = {
          hostPath = cfg.dataDir;
          isReadOnly = false;
        };
      };

      config = { lib, ... }:
        {
          services.actual = {
            enable = true;
            openFirewall = true;
            settings = {
              trustedProxies = [ hostAddress ];
              port = cfg.port;
              dataDir = dataDir;
              serverFiles = "${dataDir}/server-files";
              userFiles = "${dataDir}/user-files";
            };
          };

          users.users.actual = {
            isSystemUser = true;
            uid = lib.mkForce actualUserId;
            group = "actual";
          };

          users.groups = {
            actual = {
              gid = lib.mkForce actualGroupId;
            };
          };

          # System packages
          environment.systemPackages = with pkgs; [
            sqlite
          ];

          # Create and set permissions for required directories
          system.activationScripts.actual-dirs = ''
            mkdir -p ${dataDir}
            chown -R actual:actual ${dataDir}
            chmod -R 0700 ${dataDir}
          '';

          systemd.services = {
            actual = {            
              environment.ACTUAL_CONFIG_PATH = lib.mkForce "${dataDir}/config.json";
              serviceConfig = {
                ExecStart = lib.mkForce "${pkgs.actual-server}/bin/actual-server --config ${dataDir}/config.json";
                WorkingDirectory = lib.mkForce dataDir;
                StateDirectory = lib.mkForce dataDir;
                StateDirectoryMode = lib.mkForce 0700;
                DynamicUser = lib.mkForce false;
                ProtectSystem = lib.mkForce null;
              };
            };
          };

          networking = {
            firewall = {
              enable = true;
              allowedTCPPorts = [ cfg.port ];
            };
            # Use systemd-resolved inside the container
            # Workaround for bug https://github.com/NixOS/nixpkgs/issues/162686
            useHostResolvConf = lib.mkForce false;
          };

          services.resolved.enable = true;
          system.stateVersion = "23.11";
        };
    };

    services.traefik.dynamicConfigOptions = lib.mkIf cfg.reverseProxy.enable {
      services.actual.loadBalancer.servers = [
        {
          url = "http://${cfg.localAddress}:${toString cfg.port}";
        }
      ];
      routers.actual = {
        entryPoints = [ "websecure" ];
        rule = "Host(`${cfg.reverseProxy.host}`)";
        service = "actual";
        middlewares = cfg.reverseProxy.middlewares;
        tls.certResolver = "letsencrypt";
      };
    };

    networking = {
      nat = {
        forwardPorts = [
          {
            destination = "${cfg.localAddress}:${toString cfg.port}";
            sourcePort = cfg.port;
          }
        ];
      };
      firewall = {
        allowedTCPPorts = [ cfg.port ];
        allowedUDPPorts = [ cfg.port ];
      };
    };
  };
}
