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

let
  # XXX cannot use config.build.host.name here because infinite recursion when
  # defining  krebs.hosts.${host-name}.nets.retiolum.aliases  below.
  host-name = "xu";
in

# usage:
#   echo set_password vnc correcthorze | xu-qemu0-monitor
#
#   vncdo -s xu:1 type 'curl init.xu.r' key shift-\\ type sh key return
#
#   http://vnc.xu/vnc_auto.html?port=5701&host=xu&password=correcthorze
#
#   make [install] system=xu-qemu0 target_host=10.56.0.101

with config.krebs.lib;

{
  networking.dhcpcd.denyInterfaces = [ "qemubr0" ];

  tv.iptables.extra = {
    nat.POSTROUTING = ["-j MASQUERADE"];
    filter.FORWARD = [
      "-m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT"
      "-i qemubr0 -s 10.56.0.1/24 -m conntrack --ctstate NEW -j ACCEPT"
    ];
    filter.INPUT = [
      "-i qemubr0 -p udp -m udp --dport bootps -j ACCEPT"
      "-i qemubr0 -p udp -m udp --dport domain -j ACCEPT"
    ];
  };

  systemd.network.enable = true;
  systemd.services.systemd-networkd-wait-online.enable = false;

  services.resolved.enable = mkForce false;

  boot.kernel.sysctl."net.ipv4.ip_forward" = 1;

  systemd.network.networks.qemubr0 = {
    matchConfig.Name = "qemubr0";
    address = ["10.56.0.1/24"];
    routes = [{
      routeConfig = {
        Gateway = "*";
        Destination = "10.56.0.0";
      };
    }];
  };
  systemd.network.netdevs.qemubr0 = {
    netdevConfig = {
      Name = "qemubr0";
      Kind = "bridge";
    };
  };

  users.groups.qemu-users.gid = genid "qemu-users";

  environment.etc."qemu/bridge.conf".text = ''
    allow qemubr0
  '';

  krebs.per-user.tv.packages = [
  ];

  users.users.xu-qemu0 = {
    createHome = true;
    group = "qemu-users";
    home = "/home/xu-qemu0";
    uid = genid "xu-qemu0";
  };

  systemd.services.xu-qemu0 = let
  in {
    after = [ "network.target" "systemd-resolved.service" ];
    serviceConfig = {
      User = "xu-qemu0";
      SyslogIdentifier = "xu-qemu0";
      ExecStart = pkgs.writeDash "xu-qemu0" ''
        set -efu
        ${pkgs.coreutils}/bin/mkdir -p "$HOME/tmp"
        img=$HOME/tmp/xu-qemu0.raw
        if ! test -e "$img"; then
          ${pkgs.kvm}/bin/qemu-img create "$img" 10G
        fi
        exec ${pkgs.kvm}/bin/qemu-kvm \
            -monitor unix:$HOME/tmp/xu-qemu0-monitor.sock,server,nowait \
            -boot order=cd \
            -cdrom ${pkgs.fetchurl {
              url = https://nixos.org/releases/nixos/15.09/nixos-15.09.1012.9fe0c23/nixos-minimal-15.09.1012.9fe0c23-x86_64-linux.iso;
              sha256 = "18bc9wrsrjnhj9rya75xliqkl99gxbsk4dmwqivhvwfzb5qb5yp9";
            }} \
            -m 1024 \
            -netdev bridge,br=qemubr0,id=hn0,helper=/var/setuid-wrappers/qemu-bridge-helper \
            -net nic,netdev=hn0,id=nic1,macaddr=52:54:00:12:34:56 \
            -drive file="$img",format=raw \
            -display vnc=:1,websocket=5701,password,lossy \
            -name xu-qemu0 \
      '';
    };
  };

  krebs.setuid.xu-qemu0-monitor = {
    filename = pkgs.writeDash "xu-qemu0-monitor" ''
      exec ${pkgs.socat}/bin/socat \
          stdio \
          UNIX-CONNECT:${config.users.users.xu-qemu0.home}/tmp/xu-qemu0-monitor.sock \
    '';
    owner = "xu-qemu0";
    group = "tv";
  };

  krebs.setuid.qemu-bridge-helper = {
    filename = "${pkgs.qemu}/libexec/qemu-bridge-helper";
    group = "qemu-users";
  };

  users.users.qemu-dnsmasq.uid = genid "qemu-dnsmasq";

  # TODO need custom etc/dbus-1/system.d/dnsmasq.conf for different BusName
  services.dbus.packages = [ pkgs.dnsmasq ];

  systemd.services.qemu-dnsmasq = let
    # bind-interfaces
    conf = pkgs.writeText "qemu-dnsmasq.conf" ''
      listen-address=10.56.0.1
      interface=qemubr0
      dhcp-range=10.56.0.200,10.56.0.250
      dhcp-no-override
      dhcp-leasefile=/tmp/qemu-dnsmasq.leases
      domain=${host-name}.local
      dhcp-host=52:54:00:12:34:56,xu-qemu0,10.56.0.101,1440m
    '';
  in {
    after = [ "network.target" "systemd-resolved.service" ];
    wantedBy = [ "multi-user.target" ];
    serviceConfig = {
      Type = "dbus";
      BusName = "uk.org.thekelleys.dnsmasq";
      # -1 --enable-dbus[=uk.org.thekelleys.dnsmasq]
      SyslogIdentifier = "qemu-dnsmasq";
      ExecStart = "${pkgs.dnsmasq}/bin/dnsmasq -1k -u qemu-dnsmasq -C ${conf}";
      ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
      PrivateTmp = "true";
    };
    restartTriggers = [ config.environment.etc.hosts.source ];
  };


  krebs.nginx.servers.init = {
    server-names = [
      "init.${host-name}"
      "init.${host-name}.r"
      "init.${host-name}.retiolum"
    ];
    extraConfig = ''
      index init.txt;
      root ${pkgs.writeTextFile {
        name = "init-pages";
        text = ''
          #! /bin/sh
          set -efu

          dev=/dev/sda
          pttype=dos # gpt

          case $pttype in
            dos)
              if ! test "$(blkid -o value -s PTTYPE "$dev")" = dos; then
                parted -s "$dev" mklabel msdos
              fi
              if ! test "$(blkid -o value -s PARTLABEL "$dev"1)" = primary; then
                parted -s "$dev" mkpart primary ext4 1MiB 513MiB
                parted -s "$dev" set 1 boot on
              fi
              ;;
            gpt)
              if ! test "$(blkid -o value -s PTTYPE "$dev")" = gpt; then
                parted -s "$dev" mklabel gpt
              fi
              if ! test "$(blkid -o value -s PARTLABEL "$dev"1)" = ESP; then
                parted -s "$dev" mkpart ESP fat32 1MiB 513MiB
                parted -s "$dev" set 1 boot on
              fi
              ;;
            *)
              echo "Error: bad pttype: $pttype" >&2
              exit -1
          esac

          if ! test "$(blkid -o value -s PARTLABEL "$dev"2)" = primary; then
            parted -s "$dev" mkpart primary btrfs 513MiB 100%
          fi
          if ! test "$(blkid -o value -s TYPE "$dev"1)" = vfat; then
            mkfs.vfat "$dev"1
          fi
          if ! test "$(blkid -o value -s TYPE "$dev"2)" = btrfs; then
            mkfs.btrfs "$dev"2
          fi

          parted "$dev" print

          if ! test "$(lsblk -n -o MOUNTPOINT "$dev"2)" = /mnt; then
            mount "$dev"2 /mnt
          fi
          if ! test "$(lsblk -n -o MOUNTPOINT "$dev"1)" = /mnt/boot; then
            mkdir -m 0000 -p /mnt/boot
            mount "$dev"1 /mnt/boot
          fi

          lsblk "$dev"

          key=${shell.escape config.krebs.users.tv-xu.pubkey}

          if [ "$(cat /root/.ssh/authorized_keys 2>/dev/null)" != "$key" ]; then
            mkdir -p /root/.ssh
            echo "$key" > /root/.ssh/authorized_keys
          fi
          systemctl start sshd
          ip route
          echo READY.
        '';
        destination = "/init.txt";
      }};
    '';
  };


  krebs.hosts.${host-name}.nets.retiolum.aliases = [
    "init.${host-name}.r"
    "init.${host-name}.retiolum"
    "vnc.${host-name}.r"
    "vnc.${host-name}.retiolum"
  ];

  krebs.nginx.servers.noVNC = {
    server-names = [
      "vnc.${host-name}"
      "vnc.${host-name}.r"
      "vnc.${host-name}.retiolum"
    ];
    #rewrite ^([^.]*)$ /vnc_auto.html?host=localhost&port=5701;
    locations = singleton (nameValuePair "/" ''
      index vnc.html;
      root ${pkgs.noVNC};
    '');
  };
}