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

let
  cfg = config.services.mediawiki;
in
{
  assertions = [
    {
      assertion = lib.versions.majorMinor pkgs.mediawiki.version != 1.40;
      # https://www.mediawiki.org/wiki/Version_lifecycle
      message = "Please keep mediawiki on LTS versions which is required by the LDAP extension";
    }
  ];
  c3d2 = {
    deployment.server = "server10";
    hq.sendmail = true;
  };

  microvm.mem = 1024;

  networking = {
    firewall.allowedTCPPorts = [ 80 443 ]; # httpd, not nginx :(
    hostName = "mediawiki";
  };

  services = {
    backup.paths = [ "/var/lib/mediawiki/uploads/" ];

    logrotate.checkConfig = false;

    mediawiki = {
      enable = true;
      database = {
        type = "postgres";
        socket = "/run/postgresql";
      };

      # see https://extdist.wmflabs.org/dist/extensions/ for list of extensions
      # save them on https://web.archive.org/save and copy the final URL below
      extensions = {
        Lockdown = pkgs.fetchzip {
          url = "https://web.archive.org/web/20230710141042/https://extdist.wmflabs.org/dist/extensions/Lockdown-REL1_40-7d900ed.tar.gz";
          sha256 = "sha256-TgoL9IcwY4EBNUsoVBqpUehVO7TEDT22FoH7Ep4dMxw=";
        };
        # TODO: replace with https://www.mediawiki.org/wiki/Extension:DynamicPageList3
        intersection = pkgs.fetchzip {
          url = "https://web.archive.org/web/20230710142223/https://extdist.wmflabs.org/dist/extensions/intersection-REL1_40-f3c1559.tar.gz";
          sha256 = "sha256-/Ap56EOfsAlx/gkN8Y+NdU28yuZsZmrrBMmuNoi88/A=";
        };
        # requires PluggableAuth
        LDAPAuthentication2 =
          let
            src = pkgs.fetchzip {
              url = "https://web.archive.org/web/20230710142325/https://extdist.wmflabs.org/dist/extensions/LDAPAuthentication2-REL1_40-2864ae9.tar.gz";
              sha256 = "sha256-LWXpmgzUpgEaPe/4cwF2cmJxPkW8ywT7gRAlB58mDfY=";
            };
          in
          # TODO: remove with next release
          pkgs.runCommand "LDAPAuthentication2" { } ''
            mkdir $out
            cp -r ${src}/* $out
            sed 's/"PluggableAuth": "6.*"/"PluggableAuth": "*"/g' -i $out/extension.json
          '';
        LDAPProvider = pkgs.fetchzip {
          url = "https://web.archive.org/web/20230710141035/https://extdist.wmflabs.org/dist/extensions/LDAPProvider-REL1_40-99edc23.tar.gz";
          sha256 = "sha256-DYq5CCm//rc6Mei9K6S2Ue+hzz6PYHnwpbJouFS5j+o=";
        };
        PluggableAuth = pkgs.fetchzip {
          url = "https://web.archive.org/web/20230710142618/https://extdist.wmflabs.org/dist/extensions/PluggableAuth-REL1_40-519c6d2.tar.gz";
          sha256 = "sha256-N1+OV1UdzvU4iXhaS/+fuEoAXqrkVyyEPDirk0vrT8A=";
        };
      };

      name = "C3D2";
      nginx.hostName = "wiki.c3d2.de";

      #skins = {
      #   Vector = "${config.services.mediawiki.package}/share/mediawiki/skins/Vector";
      #   Hector = "${config.services.mediawiki.package}/share/mediawiki/skins/Hector";
      #};

      # initial admin user password
      passwordFile = config.sops.secrets."mediawiki/adminPassword".path;
      uploadsDir = "/var/lib/mediawiki/uploads";
      webserver = "nginx";

      extraConfig = /* php */ ''
        $wgAllowUserCss = true;
        $wgDBmwschema = "mediawiki";
        $wgEnableAPI = true;
        $wgEnableMWSuggest = true;
        $wgShowExceptionDetails = true;
        $wgUseAjax = true;

        $wgFavicon = "https://c3d2.de/favicon.ico";
        $wgLogos = [
          '1x' => "https://www.c3d2.de/images/ck.png",
          '1.5x' => "https://www.c3d2.de/images/ck.png",
          '2x' => "https://www.c3d2.de/images/ck.png",
          'icon' => "https://www.c3d2.de/images/ck.png",
        ];
        $wgEmergencyContact = "wiki@c3d2.de";
        $wgPasswordSender   = "wiki@c3d2.de";
        $wgLanguageCode = "de";

        $wgGroupPermissions['*']['edit'] = false;
        $wgGroupPermissions['user']['edit'] = true;
        $wgGroupPermissions['sysop']['userrights'] = true;

        define("NS_INTERN", 100);
        define("NS_INTERN_TALK", 101);

        $wgExtraNamespaces[NS_INTERN] = "Intern";
        $wgExtraNamespaces[NS_INTERN_TALK] = "Intern_Diskussion";

        $wgGroupPermissions['intern']['move'] = true;
        $wgGroupPermissions['intern']['move-subpages']    = true;
        $wgGroupPermissions['intern']['move-rootuserpages'] = true; // can move root userpages
        $wgGroupPermissions['intern']['read'] = true;
        $wgGroupPermissions['intern']['edit'] = true;
        $wgGroupPermissions['intern']['createpage'] = true;
        $wgGroupPermissions['intern']['createtalk'] = true;
        $wgGroupPermissions['intern']['writeapi'] = true;
        $wgGroupPermissions['intern']['upload'] = true;
        $wgGroupPermissions['intern']['reupload'] = true;
        $wgGroupPermissions['intern']['reupload-shared'] = true;
        $wgGroupPermissions['intern']['minoredit'] = true;
        $wgGroupPermissions['intern']['purge'] = true; // can use ?action=purge without clicking "ok"
        $wgGroupPermissions['intern']['sendemail'] = true;

        $wgNamespacePermissionLockdown[NS_INTERN]['*'] = array('intern');
        $wgNamespacePermissionLockdown[NS_INTERN_TALK]['*'] = array('intern');

        define("NS_I4R", 102);
        define("NS_I4R_TALK", 103);
        $wgExtraNamespaces[NS_I4R] = "IT4Refugees";
        $wgExtraNamespaces[NS_I4R_TALK] = "IT4Refugees_Diskussion";
        $wgGroupPermissions['i4r']['move']             = true;
        $wgGroupPermissions['i4r']['move-subpages']    = true;
        $wgGroupPermissions['i4r']['move-rootuserpages'] = true; // can move root userpages
        $wgGroupPermissions['i4r']['read']             = true;
        $wgGroupPermissions['i4r']['edit']             = true;
        $wgGroupPermissions['i4r']['createpage']       = true;
        $wgGroupPermissions['i4r']['createtalk']       = true;
        $wgGroupPermissions['i4r']['writeapi']         = true;
        $wgGroupPermissions['i4r']['upload']           = true;
        $wgGroupPermissions['i4r']['reupload']         = true;
        $wgGroupPermissions['i4r']['reupload-shared']  = true;
        $wgGroupPermissions['i4r']['minoredit']        = true;
        $wgGroupPermissions['i4r']['purge']            = true; // can use ?action=purge without clicking "ok"
        $wgGroupPermissions['i4r']['sendemail']        = true;
        $wgNamespacePermissionLockdown[NS_I4R]['*'] = array('i4r');
        $wgNamespacePermissionLockdown[NS_I4R_TALK]['*'] = array('i4r');

        $wgGroupPermissions['sysop']['deletelogentry'] = true;
        $wgGroupPermissions['sysop']['deleterevision'] = true;

        wfLoadExtension('ConfirmEdit/QuestyCaptcha');
        $wgCaptchaClass = 'QuestyCaptcha';
        $wgCaptchaQuestions[] = array( 'question' => 'How is C3D2 logo in ascii?', 'answer' => '<<</>>' );

        wfLoadExtension( 'Interwiki' );
        $wgGroupPermissions['sysop']['interwiki'] = true;

        wfLoadExtension('Cite');
        wfLoadExtension('CiteThisPage');
        wfLoadExtension('ConfirmEdit');
        wfLoadExtension('ParserFunctions');
        wfLoadExtension('WikiEditor');

        // TODO: what about $wgUpgradeKey ?

        // TODO: does this even work?
        // https://www.mediawiki.org/wiki/Extension:Scribunto#Requirements mentions quite some extra steps which we didn't do
        wfLoadExtension('Scribunto');
        $wgScribuntoDefaultEngine = 'luastandalone';

        # LDAP
        $LDAPProviderDomainConfigs = "${config.sops.secrets."mediawiki/ldapprovider".path}";
        $wgPluggableAuth_EnableLocalLogin = true;
      '';
    };

    nginx = {
      enable = true;
      commonHttpConfig = ''
        # for some reason nginx adds a port for the 301 redirect from / to /wiki/
        port_in_redirect off;
      '';
      virtualHosts."wiki.c3d2.de" = {
        enableACME = true;
        forceSSL = true;
        listen = libC.defaultListen;
        locations."/".extraConfig = lib.mkForce ''
          return 307 /wiki$request_uri;
        '';
      };
    };

    phpfpm.phpPackage = pkgs.php.buildEnv {
      extensions = { all, enabled }: enabled ++ (with all; [ apcu ]);
    };

    postgresql = {
      enable = true;
      ensureDatabases = [ cfg.database.name ];
      ensureUsers = [{
        name = cfg.database.user;
        ensurePermissions = { "DATABASE ${cfg.database.name}" = "ALL PRIVILEGES"; };
      }];
      package = pkgs.postgresql_16;
      upgrade.stopServices = [ "phpfpm-mediawiki" ];
    };
  };

  sops = {
    age.sshKeyPaths = [ "/etc/ssh/ssh_host_ed25519_key" ];
    defaultSopsFile = ./secrets.yaml;
    secrets = {
      "mediawiki/adminPassword".owner = config.systemd.services.mediawiki-init.serviceConfig.User;
      "mediawiki/ldapprovider".owner = config.systemd.services.mediawiki-init.serviceConfig.User;
      "mediawiki/secretKey" = {
        owner = config.systemd.services.mediawiki-init.serviceConfig.User;
        path = "/var/lib/mediawiki/secret.key";
      };
      "mediawiki/upgradeKey".owner = config.systemd.services.mediawiki-init.serviceConfig.User;
    };
  };

  system.stateVersion = "22.05";

  systemd.services.mediawiki-init = {
    after = [ "postgresql.service" ];
    requires = [ "postgresql.service" ];
  };
}
