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

let
  inherit (depot.ops) secrets;
in {
  services.zigbee2mqtt = {
    enable = true;
    package = pkgs.zigbee2mqtt;
    settings = {
      homeassistant = true;
      serial.port = "/dev/serial/by-id/usb-ITead_Sonoff_Zigbee_3.0_USB_Dongle_Plus_eca6e9ba6596ed11ac206b4ce259fb3e-if00-port0";
      mqtt = {
        server = "mqtt://localhost:1883";
        user = "zigbee2mqtt";
        password = "zigbee2mqtt";
      };
      frontend = {
        port = 8099;
        host = config.my.ip.tailscale6;
      };
    };
  };
  services.mosquitto = let
    localhostUsers = {
      zigbee2mqtt = {
        password = "zigbee2mqtt";
        acl = [
          "readwrite zigbee2mqtt/#"
          "readwrite homeassistant/#"
        ];
      };
      matrix2mqtt = {
        password = "matrix2mqtt";
        acl = [
          "readwrite matrix2mqtt/#"
          "readwrite homeassistant/#"
        ];
      };
      homeassistant = {
        password = "homeassistant";
        acl = [
          "readwrite matrix2mqtt/#"
          "readwrite zigbee2mqtt/#"
          "readwrite homeassistant/#"
        ];
      };
    };
  in {
    enable = true;
    listeners = [{
      address = "127.0.0.1";
      port = 1883;
      users = localhostUsers;
    } {
      address = "::1";
      port = 1883;
      users = localhostUsers;
    }];
  };

  services.home-assistant = {
    enable = true;
    configWritable = true;
    lovelaceConfigWritable = true;
    config = {
      homeassistant = {
        name = "117 Malden Road";
        time_zone = "Europe/London";
        external_url = "https://ha.lukegb.com";
        internal_url = "https://ha.lukegb.com";
      };
      notify = [{
        name = "pushover-luke";
        platform = "pushover";
      }];
      http = {
        use_x_forwarded_for = true;
        trusted_proxies = [ "::1" "127.0.0.1" ];
      };
      lifx.light = {};
      light = [{
        platform = "group";
        name = "Bedroom Lights";
        entities = map (x: "light.overhead_${x.side}_${x.n}") (lib.cartesianProduct { side = [ "left" "right" ]; n = [ "1" "2" "3" "4" ]; });
      }];
      cast = {};
      plex = {};
      default_config = {};

      broadlink = {};
      homekit = {};
      mqtt = {};
      smartthings = {};
      google_assistant = {
        project_id = "malden-homeassistant";
        service_account = secrets.homeAssistant.googleServiceAccount;
        report_state = true;
        exposed_domains = [
          "light"
        ];
      };

      scene = let
        bedroomOverhead = x: ({
          color_mode = "color_temp";
          brightness = 255;
          color_temp = 316;
        } // x);
        entityDefs = ring: overhead: let o = bedroomOverhead { state = overhead; }; in {
          "light.overhead_left_1" = o;
          "light.overhead_left_2" = o;
          "light.overhead_left_3" = o;
          "light.overhead_left_4" = o;
          "light.overhead_right_1" = o;
          "light.overhead_right_2" = o;
          "light.overhead_right_3" = o;
          "light.overhead_right_4" = o;
        };
      in [{
        name = "Bedroom Reset";
        entities = entityDefs "off" "on";
      } {
        name = "Bedroom Off";
        entities = entityDefs "off" "off";
      }];

      automation = let
        base = extra: alias: webhook_id: ({
          inherit alias;
          trigger = [{
            inherit webhook_id;
            platform = "webhook";
          }];
        } // extra);
        toggleEntity = entity_id: base {
          action = [{
            service = "homeassistant.toggle";
            target.entity_id = entity_id;
          }];
        };
        playPauseEntity = entity_id: base {
          action = [{
            service = "media_player.media_play_pause";
            target.entity_id = entity_id;
          }];
        };
        scene = scene_entity_id: base {
          action = [{
            service = "scene.turn_on";
            target.entity_id = scene_entity_id;
            data.transition = 1.0;
          }];
        };
      in [
        (toggleEntity "light.bedroom_lights" "Desk LHS Switch press - toggle room" "flic_desk_lhs")
        (scene "scene.bedroom_reset" "Desk LHS Switch hold - reset room" "flic_desk_lhs_hold")

        (toggleEntity "light.bedside_lamp" "Desk RHS Switch press - toggle bedside" "flic_desk_rhs")

        (toggleEntity "light.bedroom_lights" "Bed LHS Switch press - toggle room" "flic_bed_lhs")
        (scene "scene.bedroom_reset" "Bed LHS Switch dblpress - reset room" "flic_bed_lhs_dbl")
        (scene "scene.bedroom_off" "Bed LHS Switch dblpress - reset room" "flic_bed_lhs_hold")

        (playPauseEntity "media_player.nebula" "Bed RHS Switch press - play/pause nebula" "flic_bed_rhs")

        (toggleEntity "light.bedroom_lights" "Bedroom Door Switch press - toggle room" "flic_bedroom_door")
        (scene "scene.bedroom_off" "Bedroom Door Switch dblpress - room off" "flic_bedroom_door_dbl")
        (scene "scene.bedroom_off" "Bedroom Door Switch hold - room off" "flic_bedroom_door_hold")
      ];
    };
    lovelaceConfig = {
      title = "117 Malden Road";
      views = [{
        title = "Luke's Bedroom";
        badges = let
          scene = scene: cfg: lib.mkMerge [{
            type = "entity";
            show_name = true;
            show_state = false;
            show_icon = true;
            entity = "scene.${scene}";
            tap_action.action = "toggle";
          } cfg];
        in [(scene "bedroom_off" {
          icon = "mdi:ceiling-light-outline";
        }) (scene "bedroom_reset" {
          icon = "mdi:ceiling-light-multiple";
        })];
        cards = [{
          type = "grid";
          square = false;
          columns = 1;
          cards = [{
            type = "light";
            entity = "light.bedroom_lights";
          } {
            type = "entities";
            entities = [{
              name = "Mosquito Repellent";
              entity = "switch.lukes_bedroom_mosquitto_repellent";
            }];
          }];
        } {
          type = "grid";
          square = false;
          columns = 1;
          cards = [{
            type = "media-control";
            entity = "media_player.nebula_3";
          } {
            type = "media-control";
            entity = "media_player.shield_2";
          }];
        } {
          type = "grid";
          square = false;
          columns = 1;
          cards = [{
            title = "Projector";
            type = "entities";
            entities = [{
              name = "source";
              entity = "select.hdmi_matrix_hdmi_1_projector";
            } {
              name = "Power (CEC)";
              entity = "switch.hdmi_matrix_hdmi_1_projector_cec_power";
              icon = "mdi:power";
            }];
          } {
            title = "Sound Bar";
            type = "entities";
            entities = [{
              name = "Source";
              entity = "select.hdmi_matrix_hdmi_2_sound_bar";
            } {
              name = "Power (Samsung SmartThings)";
              entity = "switch.samsung_soundbar_q930b";
              icon = "mdi:power";
            } {
              name = "Power (CEC)";
              entity = "switch.hdmi_matrix_hdmi_2_sound_bar_cec_power";
              icon = "mdi:power";
            }];
          } {
            title = "Side Monitor";
            type = "entities";
            entities = [{
              name = "Source";
              entity = "select.hdmi_matrix_hdmi_3_desk_monitor";
            } {
              name = "Power";
              entity = "switch.hdmi_matrix_hdmi_3_desk_monitor_cec_power";
              icon = "mdi:power";
            }];
          }];
        }];
      }];
    };
  };

  services.nginx.virtualHosts."ha.lukegb.com" = {
    forceSSL = true;
    locations."/" = {
      proxyPass = "http://localhost:8123/";
      proxyWebsockets = true;
    };
  };
  my.vault.acmeCertificates."ha.lukegb.com" = {
    hostnames = [ "ha.lukegb.com" ];
    nginxVirtualHosts = [ "ha.lukegb.com" ];
  };

  services.node-red = {
    enable = true;
    withNpmAndGcc = true;
    port = 1880;
  };

  systemd.services.matrix2mqtt = {
    wantedBy = [ "multi-user.target" ];
    unitConfig = {
      StartLimitIntervalSec = "0";
    };
    serviceConfig = {
      ExecStart = "${depot.rust.matrix2mqtt}/bin/matrix2mqtt";
      User = "matrix2mqtt";
      PrivateTmp = true;
      PrivateDevices = true;
      RestrictNamespaces = true;
      RestrictRealtime = true;
      ProtectKernelLogs = true;
      ProtectControlGroups = true;
      ProtectHostname = true;
      ProtectHome = true;
      ProtectProc = "invisible";
      ProcSubset = "pid";
      ProtectKernelTunables = true;
      ProtectKernelModules = true;
      ProtectClock = true;
      CapabilityBoundingSet = "";
      LockPersonality = true;
      PrivateUsers = true;
      RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6 AF_NETLINK";

      DynamicUser = true;
      Restart = "always";
      RestartSec = "100ms";
      RestartSteps = 10;
      RestartMaxDelaySec = "1min";
    };
  };
}