{ config, lib, pkgs, ... }:
with lib;
let
  cfg = config.services.tt-rss;
  configVersion = 26;
  cacheDir = "cache";
  lockDir = "lock";
  feedIconsDir = "feed-icons";
  dbPort = if cfg.database.port == null
    then (if cfg.database.type == "pgsql" then 5432 else 3306)
    else cfg.database.port;
  poolName = "tt-rss";
  phpfpmSocketName = "/var/run/phpfpm/${poolName}.sock";
  tt-rss-config = pkgs.writeText "config.php" ''
    plugins.local directory.
        '';
      };
      themePackages = mkOption {
        type = types.listOf types.package;
        default = [];
        description = ''
          List of themes to install. The list elements are expected to
          be derivations. All elements in this derivation are automatically
          copied to the themes.local directory.
        '';
      };
      logDestination = mkOption {
        type = types.enum ["" "sql" "syslog"];
        default = "sql";
        description = ''
          Log destination to use. Possible values: sql (uses internal logging
          you can read in Preferences -> System), syslog - logs to system log.
          Setting this to blank uses PHP logging (usually to http server
          error.log).
        '';
      };
      extraConfig = mkOption {
        type = types.lines;
        default = "";
        description = ''
          Additional lines to append to config.php.
        '';
      };
    };
  };
  ###### implementation
  config = mkIf cfg.enable {
    services.phpfpm.poolConfigs = mkIf (cfg.pool == "${poolName}") {
      "${poolName}" = ''
        listen = "${phpfpmSocketName}";
        listen.owner = nginx
        listen.group = nginx
        listen.mode = 0600
        user = ${cfg.user}
        pm = dynamic
        pm.max_children = 75
        pm.start_servers = 10
        pm.min_spare_servers = 5
        pm.max_spare_servers = 20
        pm.max_requests = 500
        catch_workers_output = 1
      '';
    };
    # NOTE: No configuration is done if not using virtual host
    services.nginx = mkIf (cfg.virtualHost != null) {
      enable = true;
      virtualHosts = {
        "${cfg.virtualHost}" = {
          root = "${cfg.root}";
          locations."/" = {
            index = "index.php";
          };
          locations."~ \.php$" = {
            extraConfig = ''
              fastcgi_split_path_info ^(.+\.php)(/.+)$;
              fastcgi_pass unix:${phpfpmSocketName};
              fastcgi_index index.php;
            '';
          };
        };
      };
    };
    systemd.services.tt-rss = let
      dbService = if cfg.database.type == "pgsql" then "postgresql.service" else "mysql.service";
    in {
        description = "Tiny Tiny RSS feeds update daemon";
        preStart = let
          callSql = e:
              if cfg.database.type == "pgsql" then ''
                  ${optionalString (cfg.database.password != null) "PGPASSWORD=${cfg.database.password}"} \
                  ${pkgs.sudo}/bin/sudo -u ${cfg.user} ${config.services.postgresql.package}/bin/psql \
                    -U ${cfg.database.user} \
                    ${optionalString (cfg.database.host != null) "-h ${cfg.database.host} --port ${toString dbPort}"} \
                    -c '${e}' \
                    ${cfg.database.name}''
              else if cfg.database.type == "mysql" then ''
                  echo '${e}' | ${pkgs.sudo}/bin/sudo -u ${cfg.user} ${config.services.mysql.package}/bin/mysql \
                    -u ${cfg.database.user} \
                    ${optionalString (cfg.database.password != null) "-p${cfg.database.password}"} \
                    ${optionalString (cfg.database.host != null) "-h ${cfg.database.host} -P ${toString dbPort}"} \
                    ${cfg.database.name}''
              else "";
        in ''
          rm -rf "${cfg.root}/*"
          mkdir -m 755 -p "${cfg.root}"
          cp -r "${pkgs.tt-rss}/"* "${cfg.root}"
          ${optionalString (cfg.pluginPackages != []) ''
            for plugin in ${concatStringsSep " " cfg.pluginPackages}; do
              cp -r "$plugin"/* "${cfg.root}/plugins.local/"
            done
          ''}
          ${optionalString (cfg.themePackages != []) ''
            for theme in ${concatStringsSep " " cfg.themePackages}; do
              cp -r "$theme"/* "${cfg.root}/themes.local/"
            done
          ''}
          ln -sf "${tt-rss-config}" "${cfg.root}/config.php"
          chown -R "${cfg.user}" "${cfg.root}"
          chmod -R 755 "${cfg.root}"
        ''
        + (optionalString (cfg.database.type == "pgsql") ''
          ${optionalString (cfg.database.host == null && cfg.database.password == null) ''
            if ! [ -e ${cfg.root}/.db-created ]; then
              ${pkgs.sudo}/bin/sudo -u ${config.services.postgresql.superUser} ${config.services.postgresql.package}/bin/createuser ${cfg.database.user}
              ${pkgs.sudo}/bin/sudo -u ${config.services.postgresql.superUser} ${config.services.postgresql.package}/bin/createdb -O ${cfg.database.user} ${cfg.database.name}
              touch ${cfg.root}/.db-created
            fi
          ''}
          exists=$(${callSql "select count(*) > 0 from pg_tables where tableowner = user"} \
          | tail -n+3 | head -n-2 | sed -e 's/[ \n\t]*//')
          if [ "$exists" == 'f' ]; then
            ${callSql "\\i ${pkgs.tt-rss}/schema/ttrss_schema_${cfg.database.type}.sql"}
          else
            echo 'The database contains some data. Leaving it as it is.'
          fi;
        '')
        + (optionalString (cfg.database.type == "mysql") ''
          exists=$(${callSql "select count(*) > 0 from information_schema.tables where table_schema = schema()"} \
          | tail -n+2 | sed -e 's/[ \n\t]*//')
          if [ "$exists" == '0' ]; then
            ${callSql "\\. ${pkgs.tt-rss}/schema/ttrss_schema_${cfg.database.type}.sql"}
          else
            echo 'The database contains some data. Leaving it as it is.'
          fi;
        '');
        serviceConfig = {
          User = "${cfg.user}";
          ExecStart = "${pkgs.php}/bin/php ${cfg.root}/update.php --daemon";
          StandardOutput = "syslog";
          StandardError = "syslog";
          PermissionsStartOnly = true;
        };
        wantedBy = [ "multi-user.target" ];
        requires = ["${dbService}"];
        after = ["network.target" "${dbService}"];
    };
    services.mysql = optionalAttrs (cfg.database.type == "mysql") {
      enable = true;
      package = mkDefault pkgs.mysql;
      ensureDatabases = [ cfg.database.name ];
      ensureUsers = [
        {
          name = cfg.user;
          ensurePermissions = {
            "${cfg.database.name}.*" = "ALL PRIVILEGES";
          };
        }
      ];
    };
    services.postgresql = optionalAttrs (cfg.database.type == "pgsql") {
      enable = mkDefault true;
    };
    users = optionalAttrs (cfg.user == "tt_rss") {
      users.tt_rss = {
        description = "tt-rss service user";
        isSystemUser = true;
        group = "tt_rss";
      };
      groups.tt_rss = {};
    };
  };
}