{ pkgs, lib, config, ... }:
let
  domain = "autogeree.net";
  srv = "pleroma";
  owner = "${srv}-${domain}";
  db = "${srv}-${domain}";
  port = 4000;
  inherit (config.services) postgresql;
  inherit (config.users) groups;

  # pleroma_ctl instance gen
  # https://git.pleroma.social/pleroma/pleroma/blob/develop/config/config.exs
  pleroma-conf = ''
    import Config

    config :pleroma, Pleroma.Web.Endpoint,
       url: [host: "${srv}.${domain}", scheme: "https", port: 443],
       http: [ip: {127, 0, 0, 1}, port: ${toString port}]

    config :pleroma, :http_security,
      sts: true

    config :pleroma, Pleroma.Web.WebFinger, domain: "${domain}"

    # RELEASE_COOKIE="/var/lib/pleroma/.cookie" \
    # pleroma_ctl user new $user $user+pleroma@autogeree.net --password "$password" --moderator --admin -y
    config :pleroma, :instance,
      name: "${domain}",
      email: "root+${srv}@${domain}",
      notify_email: "root+${srv}@${domain}",
      limit: 5000,
      registrations_open: false,
      invites_enabled: true,
      description: "Pleroma: An efficient and flexible fediverse server",
      short_description: "",
      background_image: "/images/city.jpg",
      instance_thumbnail: "/instance/thumbnail.jpeg",
      max_pinned_statuses: 4

    config :pleroma, :media_proxy,
      enabled: false,
      redirect_on_failure: true
      #base_url: "https://cache.pleroma.social"

    config :pleroma, :markup,
      allow_inline_images: true,
      allow_headings: true,
      allow_tables: true

    # pleroma_ctl email test --to julm+pleroma@autogeree.net
    config :pleroma, Pleroma.Emails.Mailer, [
      adapter: Swoosh.Adapters.Sendmail,
      enabled: true,
      cmd_path: "/run/wrappers/bin/sendmail",
      cmd_args: ""
    ]

    config :pleroma, :dangerzone,
      override_repo_pool_size: true

    config :pleroma, Pleroma.Repo,
      adapter: Ecto.Adapters.Postgres,
      username: "${owner}",
      socket_dir: "/run/postgresql",
      database: "${db}",
      pool_size: 5,
      # Database task queue timeout to avoid timeouts on the front end
      # due to a slow postgresql, eg. because of a CPUQuota= hardening.
      queue_target: 20_000,
      queue_interval: 1_000,
      ownership_timeout: 20_000,
      timeout: 40_000,
      prepare: :named,
      # https://docs-develop.pleroma.social/backend/configuration/postgresql/#disable-generic-query-plans
      parameters: [
        plan_cache_mode: "force_custom_plan"
      ]

    config :pleroma, :database, rum_enabled: false
    config :pleroma, :instance, static_dir: "/var/lib/${srv}/static"
    config :pleroma, Pleroma.Uploaders.Local, uploads: "/var/lib/${srv}/uploads"
    config :pleroma, configurable_from_database: false
    config :pleroma, Pleroma.Upload, filters: [
      Pleroma.Upload.Filter.Exiftool.StripLocation,
      Pleroma.Upload.Filter.Exiftool.ReadDescription
    ]

    # https://docs-develop.pleroma.social/backend/configuration/howto_proxy/
    #config :pleroma, :http, proxy_url: {:socks5, :localhost, 9050}
    config :pleroma, :mrf,
      policies: [
        Pleroma.Web.ActivityPub.MRF.ObjectAgePolicy,
        Pleroma.Web.ActivityPub.MRF.TagPolicy,
        Pleroma.Web.ActivityPub.MRF.SimplePolicy
      ]

    config :pleroma, :media_proxy,
      enabled: true,
      proxy_opts: [
        redirect_on_failure: true
      ];
  '';
in
{
  services = {
    pleroma = {
      enable = true;
      configs = [ pleroma-conf ];
      secretConfigFile = "/run/credentials/${srv}.service/config.exs";
    };
    nginx = {
      enable = true;
      upstreams.${srv} = {
        servers."127.0.0.1:${toString port}" = {
          max_fails = 5;
          fail_timeout = "60s";
        };
        extraConfig = ''
        '';
      };
      proxyCachePath."${domain}/${srv}/proxy" = {
        enable = true;
        inactive = "720m";
        keysZoneName = "${domain}/${srv}/proxy";
        keysZoneSize = "10m";
        levels = "1:2";
        maxSize = "10g";
        useTempPath = false;
      };

      virtualHosts.${domain} = {
        locations."/.well-known/host-meta" = {
          return = "301 https://${srv}.${domain}$request_uri";
        };
      };
      virtualHosts."${srv}.${domain}" = {
        forceSSL = true;
        useACMEHost = domain;
        extraConfig = ''
          access_log /var/log/nginx/${domain}/${srv}/access.log json buffer=32k;
          error_log  /var/log/nginx/${domain}/${srv}/error.log;
        '';
        locations."/" = {
          proxyPass = "http://${srv}";
          extraConfig = ''
            add_header 'Access-Control-Allow-Origin' '*' always;
            add_header 'Access-Control-Allow-Methods' 'POST, PUT, DELETE, GET, PATCH, OPTIONS' always;
            add_header 'Access-Control-Allow-Headers' 'Authorization, Content-Type, Idempotency-Key' always;
            add_header 'Access-Control-Expose-Headers' 'Link, X-RateLimit-Reset, X-RateLimit-Limit, X-RateLimit-Remaining, X-Request-Id' always;
            if ($request_method = OPTIONS) {
                return 204;
            }
            add_header Referrer-Policy same-origin;
            add_header X-Content-Type-Options nosniff;
            add_header X-Download-Options noopen;
            add_header X-Frame-Options DENY;
            add_header X-Permitted-Cross-Domain-Policies none;
            add_header X-XSS-Protection "1; mode=block";
            client_max_body_size 16m;
            proxy_connect_timeout 90;
            proxy_http_version 1.1;
            proxy_read_timeout 90;
            proxy_redirect off;
            proxy_send_timeout 90;
            proxy_set_header Connection "upgrade";
            proxy_set_header Upgrade $http_upgrade;
          '';
        };
        locations."/proxy" = {
          proxyPass = "http://${srv}";
          extraConfig = ''
            proxy_cache ${domain}/${srv}/proxy;
            proxy_cache_lock on;
            proxy_ignore_client_abort on;
          '';
        };
      };
    };
    postgresql = {
      identMap = ''
        # MAPNAME  SYSTEM-USERNAME  PG-USERNAME
        user       root             ${owner}
        user       ${srv}           ${owner}
      '';
    };
    sanoid.datasets."rpool/var/lib/${srv}" = {
      use_template = [ "snap" ];
      daily = 31;
      monthly = 3;
      recursive = true;
    };
  };
  systemd.services = {
    nginx = {
      serviceConfig = {
        LogsDirectory = lib.mkForce [ "nginx/${domain}/${srv}" ];
      };
    };
    pleroma = {
      path = [
        pkgs.exiftool
        # For RELEASE_COOKIE
        pkgs.hexdump
        # For rand()
        pkgs.gawk
      ];
      environment.RELEASE_VM_ARGS = pkgs.writeText "vm.args" ''
        # Disable the busy-waiting.
        # https://docs-develop.pleroma.social/backend/configuration/optimizing_beam/#virtual-machine-andor-few-cpu-cores
        +sbwt none
        +sbwtdcpu none
        +sbwtdio none
      '';
      unitConfig = {
        StartLimitBurst = 5;
        StartLimitIntervalSec = "600s";
      };
      serviceConfig = {
        LoadCredentialEncrypted = [ "config.exs:${./pleroma/config.exs.cred}" ];
        SupplementaryGroups = [ groups."postgres".name ];
        TimeoutStopSec = "10s";
        Restart = "on-failure";
        RestartSec = "10s";
        MemoryAccounting = true;
        MemoryHigh = "500M";
        MemoryMax = "600M";
        # For sendmail
        NoNewPrivileges = lib.mkForce false;
      };
    };
    postgresql = {
      postStart = lib.mkAfter ''
        connection_limit=64 \
        encoding=UTF8 \
        lc_collate=fr_FR.UTF-8 \
        lc_type=fr_FR.UTF-8 \
        owner="${owner}" \
        pass="" \
        pg_createdb "${db}" >/dev/null
        pg_adduser "${db}" "${owner}" >/dev/null

        $PSQL -d "${db}" -AqtX --set ON_ERROR_STOP=1 -f - <<EOF
          --Extensions made by ecto.migrate that need superuser access
          CREATE EXTENSION IF NOT EXISTS citext;
          CREATE EXTENSION IF NOT EXISTS pg_trgm;
          CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
        EOF
      '';
    };
  };
}