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

with lib;
let
  cfg = config.services.ulogger;

  poolName = "ulogger";

  configFile = pkgs.writeTextFile {
    name = "ulogger-config";
    text = cfg.conf;
    destination = "/config.php";
  };

in
{
  options = {
    services.ulogger = {
      enable = mkEnableOption "ulogger";
      user = mkOption {
        type = types.str;
        default = "nginx";
        description = ''
          User account under which both the update daemon and the web-application run.
        '';
      };
      dataDir = mkOption {
        type = types.path;
        default = "/var/lib/ulogger";
        description = ''
          Data directory.
        '';
      };

      package = mkOption {
        type = types.package;
        default = pkgs.ulogger-server;
        description = ''
          ulogger-server package to use.
        '';
      };

      hostName = mkOption {
        type = types.str;
        description = ''
          Name of the nginx virtualhost to use and setup.
        '';
      };

      poolConfig = mkOption {
        type = types.lines;
        default = ''
          pm = dynamic
          pm.max_children = 75
          pm.start_servers = 1
          pm.min_spare_servers = 1
          pm.max_spare_servers = 20
          pm.max_requests = 500
          catch_workers_output = 1
        '';
        description = ''
          Options for uloggers's PHP pool. See the documentation on <literal>php-fpm.conf</literal> for details on configuration directives.
        '';
      };

      conf = mkOption {
        type = types.str;
        default = ''
          <?php
          /* μlogger
           *
           * Copyright(C) 2017 Bartek Fabiszewski (www.fabiszewski.net)
           *
           * This is free software; you can redistribute it and/or modify it under
           * the terms of the GNU General Public License as published by
           * the Free Software Foundation; either version 3 of the License, or
           * (at your option) any later version.
           *
           * This program is distributed in the hope that it will be useful, but
           * WITHOUT ANY WARRANTY; without even the implied warranty of
           * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
           * General Public License for more details.
           *
           * You should have received a copy of the GNU General Public License
           * along with this program; if not, see <http://www.gnu.org/licenses/>.
           */

          // This is default configuration file.
          // Copy it to config.php and customize

          // default map drawing framework
          // (gmaps = google maps, openlayers = openlayers/osm)
          //$mapapi = "gmaps";
          $mapapi = "openlayers";

          // openlayers additional map layers
          // OpenCycleMap (0 = no, 1 = yes)
          $layer_ocm = 1;
          // MapQuest-OSM (0 = no, 1 = yes)
          $layer_mq = 1;
          // osmapa.pl (0 = no, 1 = yes)
          $layer_osmapa = 1;
          // UMP (0 = no, 1 = yes)
          $layer_ump = 1;

          // default coordinates for initial map
          $init_latitude = 52.23;
          $init_longitude = 21.01;

          // you may set your google maps api key
          // this is not obligatory by now
          //$gkey = "";

          // MySQL config
          $dbhost = ""; // mysql host, eg. localhost
          $dbuser = ""; // database user
          $dbpass = ""; // database pass
          $dbname = ""; // database name
          $dbprefix = ""; // optional table names prefix, eg. "ulogger_"

          // other
          // require login/password authentication
          // (0 = no, 1 = yes)
          $require_authentication = 1;

          // all users tracks are visible to authenticated user
          // (0 = no, 1 = yes)
          $public_tracks = 0;

          // admin user, who
          // - can add new users
          // - can edit all tracks, users
          // - has access to all users locations
          // none if empty
          $admin_user = "";

          // miniumum required length of user password
          $pass_lenmin = 12;

          // required strength of user password
          //   0 = no requirements,
          //   1 = require mixed case letters (lower and upper),
          //   2 = require mixed case and numbers,
          //   3 = require mixed case, numbers and non-alphanumeric characters
          $pass_strength = 2;

          // Default interval in seconds for live auto reload
          $interval = 10;

          // Default language
          // (en, pl, de, hu)
          $lang = "en";
          //$lang = "pl";
          //$lang = "de";
          //$lang = "hu";
          //$lang = "fr";
          //$lang = "it";

          // units
          // (metric, imperial)
          $units = "metric";
          //$units = "imperial";

          ?>
        '';
        description = ''
          Contents of the ulogger configuration file (config.php)
        '';
      };
    };
  };


  config = mkIf cfg.enable {
    services.phpfpm.pools."${poolName}" = {
      user = "${cfg.user}";
      group = "nginx";
      phpPackage = pkgs.php;
      settings = {
        "listen.owner" = "nginx";
        "listen.group" = "nginx";
        "listen.mode" = "0600";
        "user" = "${cfg.user}";
        "group" = "nginx";
        "pm" = "dynamic";
        "pm.max_children" = "75";
        "pm.min_spare_servers" = "5";
        "pm.max_spare_servers" = "20";
        "pm.max_requests" = "10";
        "catch_workers_output" = "1";
        "php_admin_value[error_log]" = "/var/log/nginx/${poolName}-phpfpm-error.log";
      };
    };
    services.phpfpm.phpOptions = ''
      max_execution_time = 120
    '';

    services.nginx.enable = mkDefault true;

    services.nginx.virtualHosts."${cfg.hostName}" = {
      enableACME = false;
      forceSSL = false;
      root = "${cfg.dataDir}";

      extraConfig = ''
        index index.php;
        add_header X-Frame-Options SAMEORIGIN;
        add_header X-Content-Type-Options nosniff;
        add_header X-XSS-Protection "1; mode=block";
      '';

      locations."~ .php$" = {
        extraConfig = ''
          fastcgi_pass unix:${config.services.phpfpm.pools."${poolName}".socket};
          include ${pkgs.nginx}/conf/fastcgi_params;
          include ${pkgs.nginx}/conf/fastcgi.conf;
          fastcgi_param DOCUMENT_ROOT ${cfg.dataDir};
          fastcgi_param SCRIPT_FILENAME ${cfg.dataDir}/$fastcgi_script_name;
          fastcgi_index index.php;
        '';
      };
    };

    users.users = {
      ${cfg.user} = {
        group = "nginx";
        description = "ulogger server user";
        isSystemUser = true;
      };
    };

    systemd.services.ulogger-install = {
      description = "ulogger install service";
      wantedBy = [ "multi-user.target" ];
      before = [ "phpfpm-ulogger.service" ];
      after = [ "mysql.service" "postgresql.service" ];
      path = with pkgs; [ coreutils php phpPackages.composer postgresql ];

      serviceConfig = {
        User = cfg.user;
        Type = "oneshot";
        RemainAfterExit = "yes";
        PermissionsStartOnly = true;
      };

      preStart = ''
        mkdir -p "${cfg.dataDir}"
        mkdir -p "${cfg.dataDir}/uploads" 
        chown -R ${cfg.user}:nginx "${cfg.dataDir}"
      '';

      environment = {
        ULOGGER_ADMIN_USER = "admin";
        ULOGGER_ADMIN_PASSWORD = "\$2y\$10\$7OvZrKgonVZM9lkzrTbiou.CVhO3HjPk5y0W9L68fVwPs/osBRIMq"; # hashed "admin"
      };

      script = ''
        cd "${cfg.dataDir}"

        if [ ! -f installed ]; then
          echo "Install file not found, installing ..."
          cp -R ${cfg.package}/* ./
          cp ${configFile}/config.php ./

          psql -U ulogger < ${cfg.package}/scripts/ulogger.pgsql
          psql -d ulogger -c "INSERT INTO users (login, password, admin) VALUES ('$ULOGGER_ADMIN_USER', '$ULOGGER_ADMIN_PASSWORD', TRUE)"
          touch installed
        fi
      '';
    };
  };

  meta = with stdenv.lib; {
    maintainers = with maintainers; [ chickensoupwithrice ];
  };
}
