{ 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;
  };

  services = {
    nginx = {
      enable = true;
      package = pkgs.nginx.override {
        modules = with pkgs.nginxModules; [ rtmp ];
      };
      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;

        error_page 500 502 503 504 https://nyanlout.re/errorpages/50x.html;
      '';
      sso = {
        enable = true;
        environmentFile = "/mnt/secrets/nginx-sso.env";
        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: {
          inherit locations;
          forceSSL = true;
          enableACME = true;
        };
        simpleReverse = rport: base {
          "/" = {
            proxyPass = "http://127.0.0.1:${toString(rport)}/";
          };
        };
        authReverse = rport: 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/";
          };
          "/errorpages/" = {
            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.riot-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 {
          "/" = {
            root = "/var/www/hls/";
            extraConfig = ''
              add_header Cache-Control no-cache;
              add_header Access-Control-Allow-Origin *;
            '';
          };
        };
        "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;
        "airsonic.nyanlout.re" = simpleReverse 4040;
        "emby.nyanlout.re" = simpleReverse 8096;
        "ci.nyanlout.re" = simpleReverse 52350;
        "gitea.nyanlout.re" = simpleReverse config.services.gitea.httpPort;
        "apart.nyanlout.re" = recursiveUpdate (simpleReverse config.services.home-assistant.port) {
          locations."/" = {
            proxyWebsockets = true;
          };
        };
      };
      appendConfig = let
        rootLocation = config.services.nginx.virtualHosts."stream.nyanlout.re".locations."/".root;
      in ''
        rtmp {
          server {
            listen 1935;

            application live {
              live on;

              exec_push ${pkgs.ffmpeg}/bin/ffmpeg -i rtmp://localhost/$app/$name -async 1 -vsync -1
                          -c:v libx264 -c:a aac -b:v 768k -b:a 96k -vf "scale=720:trunc(ow/a/2)*2" -tune zerolatency -preset ultrafast -crf 28 -f flv rtmp://localhost/show/$name_mid
                          -c:v libx264 -c:a aac -b:v 1024k -b:a 128k -vf "scale=960:trunc(ow/a/2)*2" -tune zerolatency -preset ultrafast -crf 28 -f flv rtmp://localhost/show/$name_high
                          -c copy -f flv rtmp://localhost/show/$name_src 2>>${rootLocation}/ffmpeg-$name.log;
            }

            application show {
              live on;
              hls on;

              hls_path ${rootLocation};
              hls_fragment 3s;
              hls_playlist_length 60s;

              hls_variant _mid BANDWIDTH=448000; # Medium bitrate, SD resolution
              hls_variant _high BANDWIDTH=1152000; # High bitrate, higher-than-SD resolution
              hls_variant _src BANDWIDTH=4096000; # Source bitrate, source resolution
            }
          }
        }
      '';
    };

    postgresql = {
      enable = true;
      extraConfig = ''
        full_page_writes = off
      '';
    };

    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";
      extraConfig = ''
        [ui]
        DEFAULT_THEME = arc-green

        [service]
        DISABLE_REGISTRATION = true
      '';
    };

    python-ci.enable = true;

    mastodon = {
      enable = true;
      localDomain = "social.nyanlout.re";
      configureNginx = true;
      extraConfig = {
        SMTP_AUTH_METHOD = "none";
        SMTP_OPENSSL_VERIFY_MODE = "none";
      };
      smtp = {
        fromAddress = "social@nyanlout.re";
        user = "social@nyanlout.re";
        authenticate = false;
      };
      mediaPruneTimer = true;
    };
  };

  systemd.services.site-musique = let
    djangoEnv =(pkgs.python3.withPackages (ps: with ps; [ gunicorn django_2_2 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" ];
  };
}