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

with lib;

let
  nginxSsoAuth = pkgs.writeText "nginx-sso_auth.inc" ''
    # Protect this location using the auth_request
    auth_request /sso-auth;

    # Redirect the user to the login page when they are not logged in
    error_page 401 = @error401;

    location /sso-auth {
        # Do not allow requests from outside
        internal;

        # Access /auth endpoint to query login state
        proxy_pass http://127.0.0.1:${toString(config.services.nginx.sso.configuration.listen.port)}/auth;

        # Do not forward the request body (nginx-sso does not care about it)
        proxy_pass_request_body off;
        proxy_set_header Content-Length "";

        # Set custom information for ACL matching: Each one is available as
        # a field for matching: X-Host = x-host, ...
        proxy_set_header X-Origin-URI $request_uri;
        proxy_set_header X-Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    # If the user is lead to /logout redirect them to the logout endpoint
    # of ngninx-sso which then will redirect the user to / on the current host
    location /sso-logout {
        return 302 https://login.nyanlout.re/logout?go=$scheme://$http_host/;
    }

    # Define where to send the user to login and specify how to get back
    location @error401 {
        return 302 https://login.nyanlout.re/login?go=$scheme://$http_host$request_uri;
    }
  '';
in
{
  security.acme = {
    email = "paul@nyanlout.re";
    acceptTerms = true;
  };

  users.groups = {
    work = {};
    webdav = {};
  };
  users.users = {
    work = {
      isSystemUser = true;
      group = config.users.groups.work.name;
    };
    webdav = {
      isSystemUser = true;
      group = config.users.groups.webdav.name;
    };
  };

  services = {
    phpfpm.pools = {
      work = {
        user = config.users.users.work.name;
        phpPackage = pkgs.php.withExtensions ({ all, ... }: with all; [ redis filter ]);
        settings = {
          "listen.owner" = config.services.nginx.user;
          "pm" = "dynamic";
          "pm.max_children" = 75;
          "pm.start_servers" = 10;
          "pm.min_spare_servers" = 5;
          "pm.max_spare_servers" = 20;
          "pm.max_requests" = 500;
        };
      };
      drive = {
        user = config.users.users.webdav.name;
        settings = {
          "listen.owner" = config.services.nginx.user;
          "pm" = "dynamic";
          "pm.max_children" = 75;
          "pm.start_servers" = 10;
          "pm.min_spare_servers" = 5;
          "pm.max_spare_servers" = 20;
          "pm.max_requests" = 500;
        };
        phpOptions = ''
          output_buffering=off
        '';
      };
    };
    nginx = {
      enable = true;
      package = pkgs.nginx.override {
        modules = with pkgs.nginxModules; [ dav moreheaders ];
      };
      recommendedGzipSettings = true;
      recommendedOptimisation = true;
      recommendedProxySettings = true;
      recommendedTlsSettings = true;
      commonHttpConfig = ''
        map $scheme $hsts_header {
          https   "max-age=31536000; includeSubdomains; preload";
        }
        add_header Strict-Transport-Security  $hsts_header;
        add_header Referrer-Policy            origin-when-cross-origin;
      '';
      sso = {
        enable = true;
        configuration = {
          listen = {
            addr = "127.0.0.1";
            port = 8082;
          };
          login = {
            title = "LoutreOS login";
            default_method = "simple";
            hide_mfa_field = true;
            names.simple = "Username / Password";
          };
          cookie = {
            domain = ".nyanlout.re";
            secure = true;
          };
          audit_log = {
            targets = [ "fd://stdout" ];
            events = [ "access_denied" "login_success" "login_failure" "logout" ];
          };
          providers.simple = {
            enable_basic_auth = true;
            users = {
              paul = "$2y$10$RMqeJF/hUasXZ5/SLKAu4uKKp6ac6qXCaRu4OY/fIN6ZYucDXzqYm";
            };
            groups = {
              admins = [ "paul" ];
            };
          };
          acl = {
            rule_sets = [
              {
                rules = [ { field = "x-host"; regexp = ".*"; } ];
                allow = [ "@admins" ];
              }
            ];
          };
        };
      };
      virtualHosts = let
        base = locations: {
          locations = locations // {
            "@maintenance" = {
              root = "/var/www/errorpages/";
              extraConfig = ''
                rewrite ^(.*)$ /50x.html break;
              '';
            };
          };
          forceSSL = true;
          enableACME = true;
          extraConfig = ''
            error_page 500 502 503 504 = @maintenance;
          '';
        };
        simpleReverse = rport: base {
          "/" = {
            proxyPass = "http://127.0.0.1:${toString(rport)}/";
          };
        };
        authReverse = rport: zipAttrsWith (name: vs: if name == "extraConfig" then (concatStrings vs) else elemAt vs 0) [
          (base {
            "/" = {
              proxyPass = "http://127.0.0.1:${toString(rport)}/";
              extraConfig = ''
                auth_request_set $cookie $upstream_http_set_cookie;
                add_header Set-Cookie $cookie;
              '';
            };
          })
          {
            extraConfig = ''
              include ${nginxSsoAuth};
            '';
          }
        ];
      in {
        "nyanlout.re" = base {
          "/" = {
            alias = "/var/www/site-perso/";
          };
          "/maintenance/" = {
            alias = "/var/www/errorpages/";
          };
          "/.well-known/openpgpkey/" = {
            alias = "/var/lib/gnupg/wks/nyanlout.re";
            extraConfig = ''
              add_header Access-Control-Allow-Origin * always;
            '';
          };
        } // { default = true; };
        "riot.nyanlout.re" = base { "/" = { root = pkgs.element-web; }; };
        "factorio.nyanlout.re" = base { "/" = { root = "/var/www/factorio"; }; };
        "minecraft.nyanlout.re" = base { "/" = { root = "/var/www/minecraft-overviewer"; }; };
        "musique-meyenheim.fr" = base {
          "/" = {
            proxyPass = "http://unix:/run/site-musique.sock";
          };
          "/static/" = {
            alias = "/var/www/site-musique/staticfiles/";
          };
          "/media/" = {
            alias = "/var/www/site-musique/media/";
          };
        };
        "maxspiegel.fr" = base { "/" = { root = "/run/python-ci/nyanloutre/site-max"; }; };
        "stream.nyanlout.re" = base {
          "/" = {
            proxyPass = "http://10.30.135.71";
          };
        };
        "login.nyanlout.re" = simpleReverse config.services.nginx.sso.configuration.listen.port;
        "grafana.nyanlout.re" = authReverse config.services.grafana.port;
        "transmission.nyanlout.re" = authReverse config.services.transmission.port;
        "radarr.nyanlout.re" = authReverse 7878;
        "sonarr.nyanlout.re" = authReverse 8989;
        "syncthing.nyanlout.re" = authReverse 8384;
        "jackett.nyanlout.re" = authReverse 9117;
        "pgmanage.nyanlout.re" = authReverse config.services.pgmanage.port;
        "matrix.nyanlout.re" = simpleReverse 8008;
        "emby.nyanlout.re" = recursiveUpdate (simpleReverse 8096) {
          locations."/" = {
            proxyWebsockets = true;
          };
        };
        "ci.nyanlout.re" = simpleReverse 52350;
        "gitea.nyanlout.re" = simpleReverse config.services.gitea.httpPort;
        "musique.nyanlout.re" = simpleReverse config.services.navidrome.settings.Port;
        "apart.nyanlout.re" = recursiveUpdate (simpleReverse config.services.home-assistant.port) {
          locations."/" = {
            proxyWebsockets = true;
          };
        };
        # "work.rezom.eu" = base {
        #   "/" = {
        #     index = "/_h5ai/public/index.php";
        #     extraConfig = ''
        #       dav_ext_methods PROPFIND OPTIONS;
        #     '';
        #   };
        #   "~ ^/(_h5ai/public/index|random).php" = {
        #     extraConfig = ''
        #       fastcgi_split_path_info ^(.+\.php)(/.+)$;
        #       fastcgi_pass unix:${config.services.phpfpm.pools.work.socket};
        #       include ${pkgs.nginx}/conf/fastcgi_params;
        #       include ${pkgs.nginx}/conf/fastcgi.conf;
        #     '';
        #   };
        # } // {
        #   root = "/mnt/medias/iso_linux";
        #   extraConfig = ''
        #     access_log /var/log/nginx/$host.log;
        #   '';
        # };
        "drive.nyanlout.re" = base {
          "/" = {
            index = "/index.php";
            extraConfig = ''
              fastcgi_split_path_info ^(.+\.php)(/.+)$;
              fastcgi_pass unix:${config.services.phpfpm.pools.drive.socket};
              include ${pkgs.nginx}/conf/fastcgi_params;
              include ${pkgs.nginx}/conf/fastcgi.conf;

              client_max_body_size    0;
            '';
          };
        } // {
          root = "/mnt/webdav";
        };
        "rspamd.nyanlout.re" = zipAttrsWith (name: vs: if name == "extraConfig" then (concatStrings vs) else elemAt vs 0) [
          (base {
            "/" = {
              proxyPass = "http://unix:/run/rspamd/worker-controller.sock";
              extraConfig = ''
                auth_request_set $cookie $upstream_http_set_cookie;
                add_header Set-Cookie $cookie;
              '';
            };
          })
          {
            extraConfig = ''
              include ${nginxSsoAuth};
            '';
          }
        ];
      };
    };

    postgresql = {
      enable = true;
      settings = {
        full_page_writes = false;
      };
    };

    pgmanage = {
      enable = true;
      port = 10006;
      connections = {
        localhost = "hostaddr=127.0.0.1 port=5432 dbname=postgres";
      };
    };

    gitea = {
      enable = true;
      cookieSecure = true;
      httpPort = 3001;
      rootUrl = "https://gitea.nyanlout.re/";
      database = {
        type = "postgres";
        port = 5432;
        passwordFile = "/var/lib/gitea/custom/conf/database_password";
      };
      log.level = "Warn";
      disableRegistration = true;
      settings = {
        ui.DEFAULT_THEME = "arc-green";
      };
    };

    python-ci.enable = true;
  };

  systemd.services.nginx.serviceConfig = {
    ReadWritePaths = [
      "/var/www/hls"
      "/mnt/webdav"
    ];
  };

  systemd.services.phpfpm-work.serviceConfig = {
    ReadOnlyPaths = "/mnt/medias/iso_linux";
    ReadWritePaths = [
      "/mnt/medias/iso_linux/_h5ai"
    ];
  };

  systemd.services.site-musique = let
    djangoEnv =(pkgs.python3.withPackages (ps: with ps; [ gunicorn django_3 pillow setuptools ]));
  in {
    description = "Site Django de la musique de Meyenheim";
    after = [ "network.target" ];
    requires = [ "site-musique.socket" ];
    preStart = ''
      ${djangoEnv}/bin/python manage.py migrate;
      ${djangoEnv}/bin/python manage.py collectstatic --no-input;
    '';
    environment = {
      DJANGO_SETTINGS_MODULE = "site_musique.settings.prod";
      NGINX_DIRECTORY = "/var/www/site-musique";
    };
    serviceConfig = {
      DynamicUser = true;
      Group = "nginx";
      StateDirectory = "site-musique";
      WorkingDirectory = "/var/www/site-musique/";
      ReadWritePaths = [ "/var/www/site-musique/staticfiles" "/var/www/site-musique/media" ];
      EnvironmentFile = "/mnt/secrets/site-musique.env";
      ExecStart = ''${djangoEnv}/bin/gunicorn \
        --access-logfile - \
        --bind unix:/run/site-musique.sock \
        site_musique.wsgi:application
      '';
      PrivateTmp = true;
    };
  };

  systemd.sockets.site-musique = {
    description = "Site Musique socket";
    wantedBy = [ "sockets.target" ];
    listenStreams = [ "/run/site-musique.sock" ];
  };

  systemd.services.nginx-sso.serviceConfig.EnvironmentFile = "/mnt/secrets/nginx-sso.env";
}