import ./make-test-python.nix ({ pkgs, lib, ... }:

let
  configDir = "/var/lib/foobar";
in {
  name = "home-assistant";
  meta.maintainers = lib.teams.home-assistant.members;

  nodes.hass = { pkgs, ... }: {
    environment.systemPackages = with pkgs; [ mosquitto ];

    services.postgresql = {
      enable = true;
      ensureDatabases = [ "hass" ];
      ensureUsers = [{
        name = "hass";
        ensurePermissions = {
          "DATABASE hass" = "ALL PRIVILEGES";
        };
      }];
    };

    services.home-assistant = {
      enable = true;
      inherit configDir;

      # tests loading components by overriding the package
      package = (pkgs.home-assistant.override {
        extraPackages = ps: with ps; [
          colorama
        ];
        extraComponents = [ "zha" ];
      }).overrideAttrs (oldAttrs: {
        doInstallCheck = false;
      });

      # tests loading components from the module
      extraComponents = [
        "wake_on_lan"
      ];

      # test extra package passing from the module
      extraPackages = python3Packages: with python3Packages; [
        psycopg2
      ];

      config = {
        homeassistant = {
          name = "Home";
          time_zone = "UTC";
          latitude = "0.0";
          longitude = "0.0";
          elevation = 0;
        };

        # configure the recorder component to use the postgresql db
        recorder.db_url = "postgresql://@/hass";

        # we can't load default_config, because the updater requires
        # network access and would cause an error, so load frontend
        # here explicitly.
        # https://www.home-assistant.io/integrations/frontend/
        frontend = {};

        # set up a wake-on-lan switch to test capset capability required
        # for the ping suid wrapper
        # https://www.home-assistant.io/integrations/wake_on_lan/
        switch = [ {
          platform = "wake_on_lan";
          mac = "00:11:22:33:44:55";
          host = "127.0.0.1";
        } ];

        # test component-based capability assignment (CAP_NET_BIND_SERVICE)
        # https://www.home-assistant.io/integrations/emulated_hue/
        emulated_hue = {
          host_ip = "127.0.0.1";
          listen_port = 80;
        };

        # https://www.home-assistant.io/integrations/logger/
        logger = {
          default = "info";
        };
      };

      # configure the sample lovelace dashboard
      lovelaceConfig = {
        title = "My Awesome Home";
        views = [{
          title = "Example";
          cards = [{
            type = "markdown";
            title = "Lovelace";
            content = "Welcome to your **Lovelace UI**.";
          }];
        }];
      };
      lovelaceConfigWritable = true;
    };
  };

  testScript = ''
    import re

    start_all()

    # Parse the package path out of the systemd unit, as we cannot
    # access the final package, that is overriden inside the module,
    # by any other means.
    pattern = re.compile(r"path=(?P<path>[\/a-z0-9-.]+)\/bin\/hass")
    response = hass.execute("systemctl show -p ExecStart home-assistant.service")[1]
    match = pattern.search(response)
    package = match.group('path')

    hass.wait_for_unit("home-assistant.service")

    with subtest("Check that YAML configuration file is in place"):
        hass.succeed("test -L ${configDir}/configuration.yaml")

    with subtest("Check the lovelace config is copied because lovelaceConfigWritable = true"):
        hass.succeed("test -f ${configDir}/ui-lovelace.yaml")

    with subtest("Check extraComponents and extraPackages are considered from the package"):
        hass.succeed(f"grep -q 'colorama' {package}/extra_packages")
        hass.succeed(f"grep -q 'zha' {package}/extra_components")

    with subtest("Check extraComponents and extraPackages are considered from the module"):
        hass.succeed(f"grep -q 'psycopg2' {package}/extra_packages")
        hass.succeed(f"grep -q 'wake_on_lan' {package}/extra_components")

    with subtest("Check that Home Assistant's web interface and API can be reached"):
        hass.wait_until_succeeds("journalctl -u home-assistant.service | grep -q 'Home Assistant initialized in'")
        hass.wait_for_open_port(8123)
        hass.succeed("curl --fail http://localhost:8123/lovelace")

    with subtest("Check that capabilities are passed for emulated_hue to bind to port 80"):
        hass.wait_for_open_port(80)
        hass.succeed("curl --fail http://localhost:80/description.xml")

    with subtest("Check extra components are considered in systemd unit hardening"):
        hass.succeed("systemctl show -p DeviceAllow home-assistant.service | grep -q char-ttyUSB")

    with subtest("Print log to ease debugging"):
        output_log = hass.succeed("cat ${configDir}/home-assistant.log")
        print("\n### home-assistant.log ###\n")
        print(output_log + "\n")

    with subtest("Check that no errors were logged"):
        assert "ERROR" not in output_log

    with subtest("Check systemd unit hardening"):
        hass.log(hass.succeed("systemctl cat home-assistant.service"))
        hass.log(hass.succeed("systemd-analyze security home-assistant.service"))
  '';
})
