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

let
    domain = "git.25120.org";
    forgejoCustom = pkgs.callPackage ../packages/directory.nix {
        name = "forgejo-custom";
        source = ./forgejo-custom;
    };
in
{
    services.forgejo = {
        enable = true;
        database = {
            type = "postgres";
            passwordFile = "/secrets/forgejo_db_password";
            createDatabase = false;
        };
        repositoryRoot = "/data/git/repositories";
        lfs = {
            enable = true;
            contentDir = "/data/git/data/lfs";
        };
        settings = let
            python = pkgs.python311;
            docutils =
                python.withPackages (ps: with ps; [
                docutils  # Provides rendering of ReStructured Text files
                pygments  # Provides syntax highlighting
            ]);
            nbconvert = python.withPackages (ps: with ps; [
                jupyter
                ipykernel
                nbconvert
            ]);
            max_cached_jupyter_notebooks = 200;
            cached_jupyter_preview = pkgs.writeScript "cache_preview" ''
                #!${pkgs.bash}/bin/bash

                set -eu

                input_file="$1"

                command="${nbconvert}/bin/jupyter nbconvert --stdout --to html --template basic"
                cache_directory="${config.services.forgejo.stateDir}/markup_cache/jupyter"
                max_cache_file_count="${toString max_cached_jupyter_notebooks}"

                cache_file="$cache_directory/$(md5sum "$input_file" | cut -d' ' -f1)"

                if [ -e "$cache_file" ] ; then
                    >&2 echo "Using cached file $cache_file"
                    touch "$cache_file"
                else
                    (
                        if cd "$cache_directory" ; then
                            ls -t | tail -n "+$max_cache_file_count" | xargs -r rm
                        else
                            mkdir -p "$cache_directory"
                        fi
                    )
                    eval "$command \"$input_file\" > \"$cache_file\""
                fi

                cat "$cache_file"
            '';
        in
        {
            DEFAULT.APP_NAME = "${domain}";
            server = {
                SSH_PORT = lib.head config.services.openssh.ports;
                ROOT_URL = "https://${domain}/";
                HTTP_PORT = 3001;
                DOMAIN = "${domain}";
            };
            service.DISABLE_REGISTRATION = true;
            session.COOKIE_SECURE = true;
            UI.DEFAULT_THEME = "forgejo-auto";
            "markup.restructuredtext" = {
                ENABLED = true;
                FILE_EXTENSIONS = ".rst";
                RENDER_COMMAND = "${docutils}/bin/rst2html.py";
                IS_INPUT_FILE = false;
            };
            "markup.jupyter" = {
                ENABLED = true;
                FILE_EXTENSIONS = ".ipynb";
                # RENDER_COMMAND = "\"${nbconvert}/bin/jupyter nbconvert --stdout --to html --template basic \"";
                RENDER_COMMAND = "\"${cached_jupyter_preview} \"";
                IS_INPUT_FILE = true;
                # RENDER_CONTENT_MODE = "iframe";
            };
            "markup.sanitizer.jupyter.div" = { ELEMENT = "div"; ALLOW_ATTR = "class"; REGEXP = ""; };
            "markup.sanitizer.jupyter.span" = { ELEMENT = "span"; ALLOW_ATTR = "class"; REGEXP = ""; };
            "markup.sanitizer.jupyter.img" = { ELEMENT = "img"; ALLOW_ATTR = "class"; REGEXP = ""; ALLOW_DATA_URI_IMAGES = "true"; };
            "markup.sanitizer.jupyter.svg.width" = { ELEMENT = "svg"; ALLOW_ATTR = "width"; REGEXP = ""; };
            "markup.sanitizer.jupyter.svg.height" = { ELEMENT = "svg"; ALLOW_ATTR = "height"; REGEXP = ""; };
            "markup.sanitizer.jupyter.svg.viewbox" = { ELEMENT = "svg"; ALLOW_ATTR = "viewbox"; REGEXP = ""; };
            "markup.sanitizer.jupyter.svg.use" = { ELEMENT = "use"; ALLOW_ATTR = "transform"; REGEXP = ""; };
            "markup.sanitizer.jupyter.svg.g" = { ELEMENT = "g"; ALLOW_ATTR = "class"; REGEXP = ""; };
            "markup.sanitizer.jupyter.svg.path.style" = { ELEMENT = "path"; ALLOW_ATTR = "style"; REGEXP = ""; };
            "markup.sanitizer.jupyter.svg.path.d" = { ELEMENT = "path"; ALLOW_ATTR = "d"; REGEXP = ""; };
            "markup.sanitizer.jupyter.svg.path.transform" = { ELEMENT = "path"; ALLOW_ATTR = "transform"; REGEXP = ""; };
        };
    };

    services.postgresql = {
        enable = true;
        authentication = ''
          local forgejo all ident map=forgejo-users
        '';
        # Map the forgejo user to postgresql
        identMap = ''
            forgejo-users forgejo forgejo
        '';
    };

    services.nginx = {
        enable = true;
        recommendedGzipSettings = true;
        recommendedOptimisation = true;
        recommendedProxySettings = true;
        recommendedTlsSettings = true;
        virtualHosts."${domain}" = {
            enableACME = true;
            forceSSL = true;
            locations."/".proxyPass = "http://localhost:3001/";
        };
    };

    # users.users.forgejo.extraGroups = [ "keys" ];
    systemd.services.forgejo = {
        serviceConfig = {
            ReadOnlyPaths = [ "/secrets" ];
        };
        preStart = ''
            cp -frT "${forgejoCustom}/" "${config.services.forgejo.stateDir}/custom/"
            find  "${config.services.forgejo.stateDir}/custom/" -type d -exec chmod 0750 '{}' + -or -type f -exec chmod 0640 '{}' +
        '';
    };

    networking.firewall.allowedTCPPorts = [ 80 443 ];
}
