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

with lib;

let
  domaine = "nyanlout.re";

  sendMail = to: subject: message: pkgs.writeShellScriptBin "mail.sh" ''
    ${pkgs.system-sendmail}/bin/sendmail ${to} <<EOF
    From: root@nyanlout.re
    Subject: ${subject}
    ${message}
    EOF
  '';

  login_mail_alert = pkgs.writeShellScriptBin "mail_alert.sh" ''
    if [ "$PAM_TYPE" != "close_session" ] && [ "$PAM_USER" != "zfspaulfixe" ] && [ "$PAM_USER" != "synology" ] && [ "$PAM_USER" != "rezome" ]; then
      ${sendMail "paul@nyanlout.re" "SSH Login: $PAM_USER from $PAM_RHOST" "`env`"}/bin/mail.sh
    fi
  '';

  backup_mail_alert = sendMail "paul@nyanlout.re" "ERREUR: Sauvegarde Borg" "Impossible de terminer la sauvegarde. Merci de voir les logs";

  unstable = import <nixos-unstable> { };
in

{
  imports = [
    ../../services/python-ci.nix
    ../../services/sdtdserver.nix
    # /mnt/secrets/factorio_secrets.nix
    ./monitoring.nix
    ./medias.nix
    ./web.nix
  ];

  security.acme.certs = {
    "${domaine}" = {
      extraDomainNames = [
        "mail.${domaine}"
      ];
      postRun = ''
        systemctl reload dovecot2.service
      '';
    };
  };

  mailserver = {
    enable = true;
    fqdn = "mail.${domaine}";
    domains = [ domaine ];

    # A list of all login accounts. To create the password hashes, use
    # mkpasswd -m sha-512 "super secret password"
    loginAccounts = {
      "paul@${domaine}" = {
        hashedPassword = "$6$eGmy2W7kbkfHAh$/y.ZML4eYL/v14WaVwSIG2ulkUFKFk82uBmrYBDULLtqUR8hQD3/BQIrRiBtsloxrUSja8aZ.E7ypChO.OiOI/";
      };
      "claire@${domaine}" = {
        hashedPassword = "$6$Y.vlWP9./DX$NEQQOLzYftbHOvXDkKdBYFAjzIjh8mlpomDuQRq6qkkZijrdy/p6jSbrpBLhoWwVmj4j1OWekHU1f4C9xCNJk.";
      };
    };

    # Certificate setup
    certificateScheme = 1;
    certificateFile = "/var/lib/acme/${domaine}/fullchain.pem";
    keyFile = "/var/lib/acme/${domaine}/key.pem";

    # Enable IMAP and POP3
    enableImap = true;
    enablePop3 = true;
    enableImapSsl = true;
    enablePop3Ssl = true;

    # Enable the ManageSieve protocol
    enableManageSieve = true;
  };

  services = {
    postfix = {
      relayHost = "mailvps.nyanlout.re";
      relayPort = 587;
      config = {
        smtp_tls_cert_file = lib.mkForce "/var/lib/postfix/postfixrelay.crt";
        smtp_tls_key_file = lib.mkForce "/var/lib/postfix/postfixrelay.key";
      };
    };

    rspamd.workers.controller.extraConfig = ''
      secure_ip = ["0.0.0.0/0"];
    '';

    redis.enable = true;

    logrotate = {
      enable = true;
      paths = {
        nginx = {
          path = "/var/log/nginx/*.log";
          user = config.services.nginx.user;
          group = config.services.nginx.group;
          keep = 7;
          extraConfig = ''
            compress
          '';
        };
      };
    };

    fail2ban.enable = true;

    fstrim.enable = true;

    syncthing = {
      enable = true;
      dataDir = "/var/lib/syncthing";
      openDefaultPorts = true;
    };

    nfs.server = {
      enable = true;
      exports = ''
        /mnt/medias  10.30.0.0/16(ro,no_root_squash)
        /var/lib/minecraft  10.30.0.0/16(rw,no_root_squash)
      '';
      statdPort = 4000;
      lockdPort = 4001;
      mountdPort = 4002;
    };

    matrix-synapse = {
      enable = true;
      enable_registration = true;
      server_name = "nyanlout.re";
      listeners = [
        { # federation
          bind_address = "";
          port = 8448;
          resources = [
            { compress = true; names = [ "client" "webclient" ]; }
            { compress = false; names = [ "federation" ]; }
          ];
          tls = true;
          type = "http";
          x_forwarded = false;
        }
        { # client
          bind_address = "127.0.0.1";
          port = 8008;
          resources = [
            { compress = true; names = [ "client" "webclient" ]; }
          ];
          tls = false;
          type = "http";
          x_forwarded = true;
        }
      ];
      max_upload_size = "100M";
      database_type = "psycopg2";
      database_args = {
        database = "matrix-synapse";
      };
      tls_private_key_path = "/var/lib/acme/${domaine}/key.pem";
      tls_certificate_path = "/var/lib/acme/${domaine}/fullchain.pem";
      url_preview_enabled = true;
      logConfig = ''
        version: 1

        formatters:
            journal_fmt:
                format: '%(name)s: [%(request)s] %(message)s'

        filters:
            context:
                (): synapse.util.logcontext.LoggingContextFilter
                request: ""

        handlers:
            journal:
                class: systemd.journal.JournalHandler
                formatter: journal_fmt
                filters: [context]
                SYSLOG_IDENTIFIER: synapse

        root:
            level: WARNING
            handlers: [journal]

        disable_existing_loggers: False
      '';
      app_service_config_files = [
        "/var/lib/matrix-synapse/mautrix-telegram-registration.yaml"
      ];
    };

    mautrix-telegram = {
      enable = true;
      settings = {
        homeserver = {
          address = "https://matrix.nyanlout.re";
          domain = "nyanlout.re";
        };
        appservice = {
          bot_username = "loutrebot";
        };
        bridge = {
          relaybot.authless_portals = false;
          permissions = {
            "@nyanloutre:nyanlout.re" = "admin";
          };
        };
      };
      environmentFile = "/mnt/secrets/mautrix-telegram.env";
      serviceDependencies = [ "matrix-synapse.service" ];
    };

    borgbackup.jobs = {
      loutre = {
        paths = [
          "/var/certs"
          "/var/dkim"
          "/var/lib/jellyfin"
          "/var/lib/gitea"
          "/var/lib/grafana"
          "/var/lib/jackett"
          "/var/lib/matrix-synapse"
          "/var/lib/postgresql/.zfs/snapshot/borgsnap"
          "/var/lib/radarr"
          "/var/lib/sonarr"
          "/var/lib/transmission"
          "/mnt/medias/musique"
          "/mnt/medias/torrent/lidarr"
          "/mnt/medias/torrent/musique"
          "/mnt/paul-home/paul"
          "/var/sieve"
          "/var/vmail"
        ];
        exclude = [
          "/var/lib/radarr/.config/Radarr/radarr.db-wal"
          "/var/lib/radarr/.config/Radarr/radarr.db-shm"
        ];
        repo = "/mnt/backup/borg";
        encryption = {
          mode = "repokey-blake2";
          passCommand = "cat /mnt/secrets/borgbackup_loutre_encryption_pass";
        };
        startAt = "weekly";
        prune.keep = {
          within = "1d";
          weekly = 4;
          monthly = 12;
        };
        preHook = "${pkgs.zfs}/bin/zfs snapshot loutrepool/var/postgresql@borgsnap";
        readWritePaths = [ "/var/lib/postfix/queue/maildrop" ];
        postHook = ''
          ${pkgs.zfs}/bin/zfs destroy loutrepool/var/postgresql@borgsnap
          if [[ $exitStatus == 0 ]]; then
            ${pkgs.rclone}/bin/rclone --config /mnt/secrets/rclone_loutre.conf sync -v $BORG_REPO BackupStorage:default
          else
            ${backup_mail_alert}/bin/mail.sh
          fi
        '';
      };
    };

    borgbackup.repos = {
      diskstation = {
        authorizedKeys = [ "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDllbxON66dBju7sMnhX8/E0VRo3+PDYvDsHP0/FK+h8JHol4+pouLmI7KIDKYOJmSuom283OqnyZOMqk+RShTwWIFm9hOd2R9aj45Zrd9jPW2APOCec/Epgogj0bwBnc0l2v6qxkxaBMgL5DnAQ+E00uvL1UQpK8c8j4GGiPlkWJD6Kf+pxmnfH1TIm+J2XCwl0oeCkSK/Frd8eM+wCraMSzoaGiEcfMz2jK8hxDWjDxX7epU0ELF22BVCuyN8cYRoFTnV88E38PlaqsOqD5ePkxk425gDh7j/C06f8QKgnasVH2diixo92kYSd7i/RmfeXDDwAD5xqUvODczEuIdt root@DiskStation" ];
        path = "/mnt/backup_loutre/diskstation_borg";
        user = "synology";
      };
      minecraft-rezome = {
        authorizedKeys = [ "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDc1nGsSesW96k0DPMSt/chjvCrYmfgPgHG1hdUYB5x0pZPdOJaVRIlETWdoFlO+ViviC518B3TF7Qc3oJXPZMchJQl684Nukbc312juf+j9z/KT3dqD8YvKX6o5ynx1Dyq52ftrfkBAEAvzE0OfRljUPbwGBOM0dGRD4R1jbiHquTXpITlbgGTZymbwr4Jr9W9atgf5kHMiX7xOqMZcasDtUE8g+AG4ysHdpjOrBOUM9QeRbVP1bxEFP8xjqOOoET5tbkwektP4B2jaf+EHBPUy2lkwjVEKT6MaSlkJx/wMvUWp25kG9mrXgwUw1bgfOeZIsK6ztcki3l92BJQD9ip shame@minecraft.rezom.eu" ];
        path = "/mnt/backup_loutre/minecraft_rezome";
        user = "rezome";
      };
      amandoleen = {
        authorizedKeys = [ "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDPio7GmYEZLGSHOsUBV91E3brXVLbGVjGWtfMOzO0X4BRN/3sgNPvnDxjtKtRX6VwHVOnfzYFBYtL9aoMlT8r+aegwpNv75i26f1KXwIY3OCgmMhsn/ZLNuDJPUxlsMU360kYcrXtpD2uS1m3MZrupzfWptFnMBTyksFbgdIA75kbwZCXK1pKRJqTyM9mM21gzbOD6CXHE6M96ab0OEw5t1xb379zB2/x36ihcT18a2rGDJUw6PoDiR4w5bz1Ji7rGO+tuHdmahe+0iws5eU9XNuVSVOvVxeszgfVnwc7WCUhV7nCNogWyng/hpAXZExgpli5meiv99Tv1CDimy7BRe1nmu2bztAivz8kdUKd5oSMLAkVHuCxD6omAPMUDX26yOf8nXh50CAxtPlDfnKy4aGCCnNP0HH9tgkFSMvjR6JNcPyTGATWW5p1zehOA5qady2ZVP39YuDOa1N5dLt0yVcX7e2sRbVreMkwJ9AIUVGYClOiyqzwq51iSLrUq+BkUzIeR9E5p1+LQpMhoZ+lIUtvpWjbRp+gAXgbnAbRuAjemEDBTTIdjAZgrnO4ybteyZbJgEF1ItnIcQzTlCF9fsIZrgexuiC1VPj1gkVgh20j4Qh1Qt7eAltRm4PWE6//l2B0wVtHIpanHuvWrVY1qe3ddNHZKkuoLVu302T474w== paul@paul-fixe" ];
        path = "/mnt/backup_loutre/amandoleen";
        user = "amandoleen";
      };
    };

    sdtdserver.enable = false;

    factorio = {
      enable = false;
      autosave-interval = 10;
      game-name = "Shame";
      public = true;
      username = "nyanloutre";
    };

    minecraft-server = {
      enable = false;
      jvmOpts = "-Xms512m -Xmx3072m";
      eula = true;
      declarative = true;
      openFirewall = true;
      whitelist = {
        nyanloutre = "db0669ea-e332-4ca3-8d50-f5d1458f5822";
        Hautension = "f05677f4-be5a-47df-ad77-21c739180aa2";
        LordDarkKiwi = "79290cfc-0b00-484f-9c94-ab0786402de6";
        Madahin = "f5f747e3-fac2-43e8-9b9b-a67dc2f368ff";
        Hopegcx = "4497f759-2210-48db-8764-307d33011442";
        wyrd68 = "127a3021-cdc1-419f-9010-4651df9ae3af";
        sparsyateloutre = "d2ff63c1-4e9f-4b21-9bfc-decce5d987b3";
      };
      serverProperties = {
        difficulty = 2;
        gamemode = 0;
        max-players = 50;
        motd = "Hi Mark !";
        white-list = true;
      };
    };

    kresd = {
      enable = true;
    };

    home-assistant = {
      enable = true;
      config = {
        homeassistant = {
          elevation = 143;
        };
        influxdb = null;
        config = null;
        dhcp = null;
        frontend = null;
        history = null;
        http = {
          use_x_forwarded_for = true;
          trusted_proxies = [ "127.0.0.1" ];
        };
        logbook = null;
        map = null;
        mobile_app = null;
        person = null;
        script = null;
        sun = null;
        system_health = null;
        yeelight.devices = {
          "10.40.249.0".name = "Chambre";
          "10.40.249.1".name = "Bureau";
          "10.40.249.2".name = "Cuisine";
        };
        zha = null;
        esphome = null;
        light = [
          {
            platform = "group";
            name = "Salon";
            entities = [
              "light.bureau"
              "light.cuisine"
            ];
          }
        ];
        media_player = [
          {
            platform = "squeezebox";
            host = "10.30.0.1";
          }
        ];
        tplink.switch = [
          { host = "10.30.50.7"; }
        ];
        sensor = [
          {
            platform = "template";
            sensors = {
              serveur_amps = {
                friendly_name_template = "{{ states.switch.serveur.name}} Current";
                value_template = ''{{ states.switch.serveur.attributes["current_a"] | float }}'';
                unit_of_measurement = "A";
              };
              serveur_watts = {
                friendly_name_template = "{{ states.switch.serveur.name}} Current Consumption";
                value_template = ''{{ states.switch.serveur.attributes["current_power_w"] | float }}'';
                unit_of_measurement = "W";
              };
              serveur_total_kwh = {
                friendly_name_template = "{{ states.switch.serveur.name}} Total Consumption";
                value_template = ''{{ states.switch.serveur.attributes["total_energy_kwh"] | float }}'';
                unit_of_measurement = "kWh";
              };
              serveur_volts = {
                friendly_name_template = "{{ states.switch.serveur.name}} Voltage";
                value_template = ''{{ states.switch.serveur.attributes["voltage"] | float }}'';
                unit_of_measurement = "V";
              };
              serveur_today_kwh = {
                friendly_name_template = "{{ states.switch.serveur.name}} Today's Consumption";
                value_template = ''{{ states.switch.serveur.attributes["today_energy_kwh"] | float }}'';
                unit_of_measurement = "kWh";
              };
            };
          }
        ];
        switch = [
          {
            platform = "wake_on_lan";
            name = "PC Fixe";
            mac = "b4:2e:99:ed:24:26";
            host = "10.30.135.71";
            broadcast_address = "10.30.255.255";
          }
        ];
        device_tracker = [
          {
            platform = "ping";
            hosts = { telephone_paul = "10.30.50.2"; };
          }
        ];
        scene = [
          {
            name = "Movie";
            icon = "mdi:movie-open";
            entities = {
              "light.salon" = {
                state = "on";
                xy_color = [0.299 0.115];
                brightness = 50;
              };
              "light.bande_led_tv" = {
                state = "on";
                effect = "Movie";
                brightness = 180;
              };
              "light.bande_led_bureau" = {
                state = "on";
                xy_color = [0.299 0.115];
                brightness = 130;
              };
            };
          }
          {
            name = "Home";
            icon = "mdi:home";
            entities = {
              "light.salon" = {
                state = "on";
                kelvin = 2700;
                brightness = 255;
              };
            };
          }
          {
            name = "Night";
            icon = "mdi:weather-night";
            entities = {
              "light.salon" = {
                state = "off";
              };
              "light.bande_led_tv" = {
                state = "off";
              };
              "light.bande_led_bureau" = {
                state = "off";
              };
              "light.chambre" = {
                state = "on";
                kelvin = 1900;
                brightness = 50;
              };
            };
          }
        ];
        automation = let
          min_sun_elevation = 4;

          switch_chambre = {
            domain = "zha";
            platform = "device";
            device_id = "3329ecdcad244e5e8fc0f4b96d52ffe1";
          };

          switch_entree = {
            domain = "zha";
            platform = "device";
            device_id = "7cd814190ec543dba76a7aa7e7996c41";
          };

          remote = {
            domain = "zha";
            platform = "device";
            device_id = "d1230b76264e483388a8fdaad4f44143";
          };
        in [
          # ENTREE

          {
            alias = "Aziz lumière";
            trigger = [
              {
                platform = "numeric_state";
                entity_id = "sun.sun";
                value_template = "{{ state.attributes.elevation }}";
                below = min_sun_elevation;
              }
            ];
            condition = [
              {
                condition = "state";
                entity_id = "person.paul";
                state = "home";
              }
              # Sun below max elevation
              {
                condition = "template";
                value_template = "{{ state_attr('sun.sun', 'elevation') < ${toString min_sun_elevation} }}";
              }
            ];
            action = {
              scene = "scene.home";
            };
          }
          {
            alias = "Aziz lumière switch";
            trigger = {
              type = "remote_button_short_press";
              subtype = "turn_on";
            } // switch_entree;
            action = {
              scene = "scene.home";
            };
          }
          {
            alias = "Adios";
            trigger = [
              {
                platform = "state";
                entity_id = "person.paul";
                to = "not_home";
              }
              ({
                type = "remote_button_short_press";
                subtype = "turn_off";
              } // switch_entree)
            ];
            action = [
              {
                service = "light.turn_off";
                entity_id = "all";
              }
              {
                service = "media_player.turn_off";
                entity_id = "all";
              }
            ];
          }

          # REMOTE

          {
            alias = "Button toggle";
            trigger = {
              type = "remote_button_short_press";
              subtype = "turn_on";
            } // remote;
            action = {
              choose = {
                conditions = {
                  condition = "template";
                  value_template = ''
                    {% set domain = 'light' %}
                    {% set state = 'off' %}
                    {{ states[domain] | count == states[domain] | selectattr('state','eq',state) | list | count }}
                  '';
                };
                sequence = {
                  scene = "scene.home";
                };
              };
              default = {
                service = "light.turn_off";
                entity_id = "all";
              };
            };
          }
          {
            alias = "Button scene movie";
            trigger = {
              type = "remote_button_short_press";
              subtype = "right";
            } // remote;
            action = {
              scene = "scene.movie";
            };
          }
          {
            alias = "Button scene home";
            trigger = {
              type = "remote_button_short_press";
              subtype = "left";
            } // remote;
            action = {
              scene = "scene.home";
            };
          }
          {
            alias = "Button light up";
            trigger = {
              type = "remote_button_short_press";
              subtype = "dim_up";
            } // remote;
            action = {
              service = "light.turn_on";
              entity_id = "light.salon";
              data = {
                brightness_step = 25;
              };
            };
          }
          {
            alias = "Button light down";
            trigger = {
              type = "remote_button_short_press";
              subtype = "dim_down";
            } // remote;
            action = {
              service = "light.turn_on";
              entity_id = "light.salon";
              data = {
                brightness_step = -25;
              };
            };
          }

          # CHAMBRE

          {
            alias = "Button scene night";
            trigger = {
              type = "remote_button_short_press";
              subtype = "turn_on";
            } // switch_chambre;
            action = {
              scene = "scene.night";
            };
          }
          {
            alias = "Button scene dodo";
            trigger = {
              type = "remote_button_short_press";
              subtype = "turn_off";
            } // switch_chambre;
            action = {
              service = "light.turn_off";
              entity_id = "all";
            };
          }
          {
            alias = "Button scene lumière chambre ON";
            trigger = {
              type = "remote_button_long_press";
              subtype = "dim_up";
            } // switch_chambre;
            action = {
              service = "light.turn_on";
              entity_id = "light.chambre";
            };
          }
          {
            alias = "Button scene lumière chambre OFF";
            trigger = {
              type = "remote_button_long_press";
              subtype = "dim_down";
            } // switch_chambre;
            action = {
              service = "light.turn_off";
              entity_id = "light.chambre";
            };
          }
        ];
      };
    };
  };

  dogetipbot-telegram.enable = true;

  ipmihddtemp.enable = true;

  # systemd.services.minecraft-overviewer =
  # let
  #   clientJar = pkgs.fetchurl {
  #     url = "https://overviewer.org/textures/1.14";
  #     sha256 = "0fij9wac7vj6h0kd3mfhqpn0w9gl8pbs9vs9s085zajm0szpr44k";
  #     name = "client.jar";
  #   };
  #   configFile = pkgs.runCommand "overviewer-config" { CLIENT_JAR = clientJar; } ''
  #     substitute ${./config-overviewer.py} $out \
  #       --subst-var CLIENT_JAR
  #   '';
  # in
  # {
  #   script = ''
  #     ${pkgs.minecraft-overviewer}/bin/overviewer.py --config ${configFile}
  #     ${pkgs.minecraft-overviewer}/bin/overviewer.py --config ${configFile} --genpoi
  #     rm /var/www/minecraft-overviewer/progress.json
  #   '';
  #   serviceConfig = {
  #     User = "nginx";
  #     Group = "nginx";
  #   };
  # };

  # systemd.timers.minecraft-overviewer = {
  #   wantedBy = [ "multi-user.target" ];
  #   timerConfig = {
  #     OnCalendar = "*-*-* 04:00:00";
  #   };
  # };

  # systemd.packages = with pkgs; [
  #   tgt
  # ];

  # environment.etc."tgt/targets.conf".text = ''
  #   <target iqn.2019-11.nyanlout.re:steam>
  #     backing-store /dev/zvol/loutrepool/steam-lun
  #     initiator-address 10.30.50.3
  #   </target>
  # '';

  users.groups.nginx.members = [ "matrix-synapse" ];

  security.pam.services.sshd.text = pkgs.lib.mkDefault( pkgs.lib.mkAfter "session optional ${pkgs.pam}/lib/security/pam_exec.so seteuid ${login_mail_alert}/bin/mail_alert.sh" );

  networking = {
    wireguard.interfaces = {
      wg0 = {
        ips = [ "192.168.20.1/24" ];
        privateKeyFile = "/mnt/secrets/wireguard/wg0.privatekey";
        listenPort = 51820;
        allowedIPsAsRoutes = true;
        peers = [
          {
            allowedIPs = [ "192.168.20.2/32" ];
            publicKey = "b/SXiqo+GPdNOc54lyEVeUBc6B5AbVMKh+g5EZPGzlE=";
          }
        ];
      };
    };

    nat.internalInterfaces = [ "wg0" ];
    nat.internalIPs = [ "192.168.20.0/24" ];

    firewall.interfaces.eno2.allowedTCPPorts = [
      3260
    ];

    firewall.allowedTCPPorts = [
      8448 # Matrix federation
      20 21 # FTP
    ];

    firewall.allowedTCPPortRanges = [
      { from = 64000; to = 65535; } # FTP
    ];

    firewall.allowedUDPPorts = [
      config.networking.wireguard.interfaces.wg0.listenPort
    ];
  };
}