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

with lib;

let
  cfg = config.services.breve;
  dataDir = "/var/lib/breve";

  configFile = pkgs.writeText "breve.conf" ''
    hostname = "${cfg.hostname}"
    port     = ${toString cfg.port}
    baseurl  = "${cfg.baseUrl}"
    urltable = "${dataDir}/urls"
    tls {
      cert  = "${cfg.certificate}"
      key   = "${cfg.key}" 
    }
  '';

in {

  options.services.breve = {
    enable = mkEnableOption ''
      Breve: a url shortner service.
    '';

     openPorts = mkOption {
       type = types.bool;
       default = false;
       example = literalExample "true";
       description = ''
         Open the default ports in the firewall:
           - TCP 443 (or specific port) for HTTPS
           - TCP 80  (or specific port) for HTTP->HTTPS redirect
       '';
     };

     user = mkOption {
       type = types.str;
       default = "breve";
       description = ''
         Breve will run under this user (user will be created if it doesn't exist.
         This can be your user name).
       '';
     };

     hostname = mkOption {
       type = types.str;
       default = config.networking.hostName;
       description = ''
         Breve will bind and generate URLs accorting to this hostname.
       '';
     };

     baseUrl = mkOption {
      type = types.str;
      default = "https://localhost:3000/";
      example = "https://example.com";
      description = ''
        URL to reach the breve index page. Needed in case Breve is served by 
        a reverse proxy on a different url.
      '';
     };

     port = mkOption {
       type = types.int;
       default = 443;
       example = 8080;
       description = ''
        Breve main interface will be listening on this port.
       '';
     };

     certificate = mkOption {
       type = types.path;
       default = "${dataDir}/breve.crt";
       description = ''
         The TLS certificate that Breve will be using to encrypt traffic.
       '';
     };

     key = mkOption {
       type = types.path;
       default = "${dataDir}/breve.key";
       description = ''
         The TLS key that Breve will be using to encrypt traffic.
       '';
     };

     certificateChain = mkOption {
       type = types.listOf types.path;
       default = [];
       description = ''
         List of paths to the TLS certificates chain.
       '';
     };
  };

  config = mkIf cfg.enable {

    users.extraUsers."${cfg.user}" = {
      isSystemUser = true;
      description = "Breve daemon user";
    };

    networking.firewall = mkIf cfg.openPorts {
      allowedTCPPorts = [ cfg.port ]
      ++ optional (cfg.port == 443) 80;
    };

    systemd.services.breve = {
      description = "breve: url shortner";
      wants    = [ "network.target" ];
      wantedBy = [ "multi-user.target" ];

      environment.XDG_CONFIG_HOME = "${dataDir}/conf";
      serviceConfig = {
        User      = cfg.user;
        ExecStart = "${pkgs.haskellPackages.breve}/bin/breve";
        Restart   = "on-failure";
        StateDirectory = "breve";
      };

      preStart = ''
        # link configuration
        mkdir -p ${dataDir}/conf
        if [ "$(realpath ${dataDir}/conf/breve)" != "${configFile}" ]; then
          rm -f ${dataDir}/conf/breve
          ln -s ${configFile} ${dataDir}/conf/breve
        fi
      '';

    };

  };

}