{
  config,
  lib,
  pkgs,
  namespace,
  ...
}:
let
  cfg = config.${namespace}.services.home-assistant;
  mosquittoPort = 1883;
  zigbee2mqttPort = 8080;

  # In configuration.nix or a separate file
  python-steam = pkgs.python3Packages.buildPythonPackage rec {
    pname = "steam";
    version = "1.4.4";
    pyproject = false;
    src = pkgs.fetchPypi {
      inherit pname version;
      sha256 = "sha256-K1vWkRwNSnMS9EG40WK52NR8i+u478bIhnOTsDI/pS4=";
    };

    buildInputs = with pkgs.python3Packages; [ setuptools ];

    doCheck = false; # no tests in the PyPI tarball
  };
in
{
  imports = [ ./options.nix ];

  config = lib.mkIf cfg.enable {
    # imports = [ ./hacs ];

    services.home-assistant = {
      enable = true;
      openFirewall = true;
      configDir = "/var/lib/homeassistant";
      configWritable = true; # todo
      extraComponents = [
        "adguard"
        "apple_tv"
        "analytics"
        "backup"
        "bluetooth"
        "bluetooth_adapters"
        "bluetooth_le_tracker"
        "bluetooth_tracker"
        "brother"
        "caldav"
        "calendar"
        "cloudflare"
        "co2signal"
        "color_extractor"
        "esphome"
        "ffmpeg"
        "google_translate"
        "holiday"
        "homekit"
        "isal"
        "jellyfin"
        "met"
        "music_assistant"
        "mqtt"
        "nut"
        "nextcloud"
        "nws"
        "ollama"
        "onedrive"
        "ping"
        "radio_browser"
        "samsungtv"
        "season"
        "shopping_list"
        "simplefin"
        "smartthings"
        "subaru"
        "upnp"
        "vesync"
        "workday"
        "wyoming"
        "zha"
      ];

      customComponents = with pkgs.home-assistant-custom-components; [
        # nixpkgs
        auth-header
        localtuya

        # packages
        pkgs.${namespace}.ha-anycubic
        pkgs.${namespace}.ha-bambulab
        pkgs.${namespace}.ha-gehome
        pkgs.${namespace}.ha-icloud3
        pkgs.${namespace}.ha-mail-and-packages
        pkgs.${namespace}.ha-nanokvm
        pkgs.${namespace}.ha-openhasp
        pkgs.${namespace}.ha-overseerr
        pkgs.${namespace}.ha-petlibro
        pkgs.${namespace}.ha-wyzeapi
      ];

      customLovelaceModules = with pkgs.home-assistant-custom-lovelace-modules; [
        atomic-calendar-revive
        bubble-card
        button-card
        hourly-weather
        mini-graph-card
        mini-media-player
        multiple-entity-row
        mushroom
        vacuum-card
        weather-chart-card
        zigbee2mqtt-networkmap
      ];
      # use postgresql instead of sqlite
      extraPackages =
        ps: with ps; [
          # Core functionality
          aiohttp
          aiodns
          paho-mqtt
          pillow
          pytz
          pyyaml
          sqlalchemy

          # Discovery & networking
          zeroconf
          netdisco
          ifaddr
          ssdp

          # Device protocols
          pyserial # Serial communications
          bluepy # Bluetooth LE

          # Smart home ecosystems
          mutagen # Media file metadata
          pysonos # Sonos
          pywemo # Belkin WeMo
          python-miio # Xiaomi devices
          python-kasa # TP-Link

          # Sensors & monitoring
          meteocalc # Weather calculations
          speedtest-cli # Internet speed

          # Visualization & UI
          matplotlib # Graphing

          # Security
          bcrypt
          cryptography
          pyjwt

          # Media
          ha-ffmpeg # Camera streams

          # Specialized integrations
          python-matter-server # Matter protocol

          # System integrations
          psutil # System monitoring

          psycopg2
          numpy
          hassil
          pyturbojpeg
          paho-mqtt
          pychromecast
          pyatv
          python-otbr-api
          brother
          pyipp
          govee-ble
          adguardhome
          nextcord
          aiogithubapi
          jellyfin-apiclient-python
          pylitterbot
          dateparser
          aionut
          nextcloudmonitor
          ollama
          pynecil
          aiopyarr
          pysabnzbd
          getmac
          zigpy
          bellows # For Zigbee EmberZNet-based adapters
          zigpy-xbee # For XBee adapters
          zigpy-deconz # For ConBee/RaspBee adapters
          pyicloud # iCloud
          pyatv # Apple TV
          opencv-python
          face-recognition
          ibeacon-ble
          gehomesdk
          onedrive-personal-sdk
          python-roborock
          python-steam
          apple-weatherkit

          samsungctl
          samsungtvws

          aiohomekit

          icmplib
          aioelectricitymaps
          wyoming
          pysmartthings
          wakeonlan
          ephem
        ];

      config = {
        # Includes dependencies for a basic setup
        # https://www.home-assistant.io/integrations/default_config/
        default_config = { };

        cloud = false;

        frontend = {
          themes = "!include_dir_merge_named themes";
        };

        "automation ui" = "!include automations.yaml";
        "scene ui" = "!include scenes.yaml";
        "script ui" = "!include scripts.yaml";

        http = {
          use_x_forwarded_for = true;
          trusted_proxies = [
            "172.30.33.0/24"
            "10.0.1.4"
            "10.0.1.3"
            "10.0.1.18"
            "10.0.1.0/24"
          ];
        };

        recorder = {
          db_url = "postgresql://@/hass";
          purge_keep_days = 180;
        };

        auth_header = {
          debug = false;
          username_header = "X-authentik-username";
        };

        # https://www.home-assistant.io/integrations/ota_updater/
        zha.zigpy_config.ota.z2m_remote_index = "https://raw.githubusercontent.com/Koenkk/zigbee-OTA/master/index.json";

        openhasp = {
          plate = {
            objects = [
              {
                obj = "p0b1"; # temperature label on all pages
                properties = {
                  "text" = ''{{ states("sensor.thermostat_current_temperature") }}°F'';
                };
              }
              {
                obj = "p1b2"; # light-switch toggle button
                properties = {
                  "val" = ''{{ 1 if states("light.living_room_lights") == "on" else 0 }}'';
                  "text" = ''{{ "\uE6E8" if is_state("light.living_room_lights", "on") else "\uE335" | e }}'';
                };
                event = {
                  "up" = {
                    service = "homeassistant.toggle";
                    entity_id = "light.living_room_lights";
                  };
                };
              }
              {
                obj = "p1b3"; # dropdown
                event = {
                  "changed" = {
                    service = "persistent_notification.create";
                    data = {
                      message = "I like {{ text }}";
                    };
                  };
                };
              }
            ];
          };
        };
      };
    };

    # https://www.home-assistant.io/integrations/automation/
    # systemd.tmpfiles.rules = [
    #   "f ${config.services.home-assistant.configDir}/automations.yaml 0755 hass hass"
    # ];

    # This bypasses the component validation and places it directly in HA's data directory
    system.activationScripts.installCustomComponents = ''
      chown -R hass:hass ${config.services.home-assistant.configDir}
      chmod -R 750 ${config.services.home-assistant.configDir}
    '';

    services = {
      postgresql = {
        enable = true;
        ensureDatabases = [ "hass" ];
        ensureUsers = [
          {
            name = "hass";
            ensureDBOwnership = true;
          }
        ];
      };

      # Enable and configure Mosquitto MQTT broker
      mosquitto = {
        enable = true;
        listeners = [
          {
            acl = [ "pattern readwrite #" ];
            omitPasswordAuth = true;
            settings.allow_anonymous = true;
          }
        ];
      };

      zigbee2mqtt = {
        enable = true;
        settings = {
          homeassistant = {
            enabled = config.services.home-assistant.enable;
            # Optional: Home Assistant discovery topic (default: shown below)
            # Note: should be different from [MQTT base topic](../mqtt.md) to prevent errors in HA software
            discovery_topic = "homeassistant";
            # Optional: Home Assistant status topic (default: shown below)
            status_topic = "homeassistant/status";
            # Optional: Experimental support for Home Assistant event entities, may break in the future (default: shown below) when enabled:
            # - An `event` entity will be discovered for each 'action'.
            # - The `event_type` attribute will contain the action itself, additional attributes like `button` will have further information.
            experimental_event_entities = false;
            # Optional: Home Assistant legacy action sensor (default: `false`), when enabled:
            # - Zigbee2MQTT will send an empty 'action' after one has been send
            # - A 'sensor_action' will be discovered
            legacy_action_sensor = false;
          };

          permit_join = true;
          # Web interface
          frontend = {
            port = zigbee2mqttPort; # Choose an available port
          };
          # MQTT configuration
          mqtt = {
            base_topic = "zigbee2mqtt";
            server = "mqtt://localhost:1883";
            # If using authentication:
            # user = "mqttuser";
            # password = "your-password";
          };
          serial = {
            port = "/dev/ttyUSB0";
          };
        };
      };

      music-assistant = {
        enable = true;
        providers = [
          # "airplay" # music-assistant: airplay support is missing libraop, a library we will not package because it depends on OpenSSL 1.1.
          "apple_music"
          "bluesound"
          "builtin"
          "chromecast"
          "deezer"
          "dlna"
          "fanarttv"
          "filesystem_local"
          "filesystem_smb"
          "fully_kiosk"
          "hass"
          "hass_players"
          "jellyfin"
          "musicbrainz"
          "opensubsonic"
          "player_group"
          "plex"
          "qobuz"
          "radiobrowser"
          "siriusxm"
          "snapcast"
          "sonos"
          "sonos_s1"
          "soundcloud"
          "spotify"
          "template_player_provider"
          "test"
          "theaudiodb"
          "tidal"
          "tunein"
          "ytmusic"
        ];
      };

      # Enable AirPlay
      pipewire = {
        # opens UDP ports 6001-6002
        raopOpenFirewall = true;

        extraConfig.pipewire = {
          "10-airplay" = {
            "context.modules" = [
              {
                name = "libpipewire-module-raop-discover";

                # increase the buffer size if you get dropouts/glitches
                # args = {
                #   "raop.latency.ms" = 500;
                # };
              }
            ];
          };
        };
      };
    };

    # Enable required hardware support for the Zigbee adapter
    hardware.bluetooth.enable = true; # Some adapters use Bluetooth

    # Ensure proper permissions for Zigbee USB devices
    # services.udev.extraRules = ''
    #   # For CC2531, CC2530, CC1352P-2, CC2538 and similar adapters
    #   SUBSYSTEM=="tty", ATTRS{idVendor}=="0451", ATTRS{idProduct}=="16a8", SYMLINK+="zigbee", MODE="0666"
    #   SUBSYSTEM=="tty", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7523", SYMLINK+="zigbee", MODE="0666"

    #   # For ConBee/RaspBee by Dresden Elektronik
    #   SUBSYSTEM=="tty", ATTRS{idVendor}=="1cf1", ATTRS{idProduct}=="0030", SYMLINK+="zigbee", MODE="0666"

    #   # For Electrolama zig-a-zig-ah (zzh!)
    #   SUBSYSTEM=="tty", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7523", SYMLINK+="zigbee", MODE="0666"
    # '';

    environment.systemPackages = with pkgs; [
      mosquitto # MQTT command-line tools
      usbutils # For lsusb to help identify your adapter
    ];

    networking.firewall.allowedTCPPorts = [
      mosquittoPort
      zigbee2mqttPort
      8095
      8097
    ];
  };
}
