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

let
  cfg = config.services.docs-to-host;

  # https://pagefind.app/docs/ui-usage/
  pagefind-default-ui = ''
    <link href="/pagefind/pagefind-ui.css" rel="stylesheet">
    <script src="/pagefind/pagefind-ui.js"></script>
    <div id="search"></div>
    <script>
      window.addEventListener('DOMContentLoaded', (event) => {
        new PagefindUI({ element: "#search", showSubResults: true });
      });
    </script>
  '';
  # TODO: symlink dotfiles to $out
  # TODO: ability to set fallback for unknown languages, instead of --force-language en
  # TODO: for some reason pagefind is not able to work with symlinks as input. is it a one-file-system restriction?
  # TODO: for some reason pagefind requires write access to other files than pagefind/
  addPagefindIndex = root: pkgs.runCommand "${root.name}-with-pagefind" {
    nativeBuildInputs = [ cfg.pagefind.package pkgs.rsync ];
  } ''
    #mkdir $out
    #cd $out
    #ln -s ${root}/* .

    # workaround pagefind shortcomings...
    mkdir foobar
    cd foobar
    time rsync -r --chmod +rw --copy-links ${root}/ .

    test ! -e pagefind || {
      >&2 echo 'ERROR: `root` input has `pagefind` already in it!'
      false
    }

    pagefind --site . --force-language en

    mkdir $out
    ln -s ${root}/* $out/
    cp -a pagefind $out
  '';
in

{
  options = {
    services.docs-to-host.enable = lib.mkEnableOption "docs-to-host";
    services.docs-to-host.pagefind = {
      enable = lib.mkEnableOption "pagefind default on index of docs";
      package = lib.mkPackageOption pkgs "pagefind" { };
    };
    services.docs-to-host.docs = lib.mkOption {
      type = lib.types.listOf (lib.types.submodule {
        options = {
          dirname = lib.mkOption {
            type = lib.types.str;
            example = "linux-doc";
            description = "The relative dirname at which the documentation will be linked";
          };
          basename = lib.mkOption {
            type = lib.types.str;
            example = "foobar.html";
            default = "";
            description = "The basename to which the documentation entry will be linked. Not needed if index.html exists";
          };
          path = lib.mkOption {
            type = lib.types.path;
            example = lib.literalExpression "pkgs.fetchzip {...}";
            description = "The static html documentation to host";
          };
          desc = lib.mkOption {
            type = lib.types.str;
            description = "A short decription about the hosted documentation";
          };
        };
      });
      default = [ ];
      #description = ''TODO'';
    };
  };

  # TODO: host man pages (man -H)

  config = let
    mkLinkFarmEntry = {dirname, path, ...}: {
      name = dirname;
      path = path;
    };
    mkRow = {dirname, basename, path, desc}:
      ''<tr><td><a href="${dirname}/${basename}">${dirname}</a><td>${desc}'';
    root = pkgs.linkFarm "docs-html" ([{name = "index.html"; path = pkgs.writeText "docs-index.html" ''
      <!DOCTYPE html>
      ${lib.optionalString cfg.pagefind.enable
        pagefind-default-ui
      }
      <table>
      <tr><th>URL<th>Desc
      ${lib.concatStringsSep "\n" ( builtins.map mkRow cfg.docs ) }
      </table>
    '';
    }] ++ (builtins.map mkLinkFarmEntry cfg.docs));
  in {

    # i assume we import this if needed
    services.docs-to-host.enable = lib.mkDefault true;
    services.docs-to-host.pagefind.enable = lib.mkDefault true;

    services.nginx.virtualHosts.${mkDomain "docs"} = lib.mkIf cfg.enable {
      forceSSL   = true; # addSSL = true;
      enableACME = true; #useACMEHost = acmeDomain;
      root = if cfg.pagefind.enable
        then addPagefindIndex root
        else root;
    };
  };
}
