{ ... }: {
  flake.nixosModules.systemServiceImmich =
    { config, lib, pkgs, ... }:
    let
      cfg = config.chiasson.system.services.immich;
    in
    {
      options.chiasson.system.services.immich = with lib; {
        enable = mkEnableOption "Immich stack (server + machine-learning + redis + postgres).";

        version = mkOption {
          type = types.str;
          default = "release";
          description = "Immich image tag to deploy.";
        };

        host = mkOption {
          type = types.str;
          default = "0.0.0.0";
          description = "Host interface to bind Immich server.";
        };

        port = mkOption {
          type = types.int;
          default = 2283;
          description = "Host TCP port mapped to Immich server port 2283.";
        };

        openFirewall = mkOption {
          type = types.bool;
          default = true;
          description = "Open firewall for Immich server port.";
        };

        timezone = mkOption {
          type = types.str;
          default = "UTC";
          description = "Timezone passed to Immich services via TZ.";
        };

        uploadLocation = mkOption {
          type = types.str;
          default = "/var/lib/immich/library";
          description = "Host path used for Immich uploads/library.";
        };

        environmentFiles = mkOption {
          type = types.listOf types.path;
          default = [ ];
          description = ''
            Docker `--env-file` paths for **immich-database** and **immich-server** (after inline `-e`).
            Use a sops template with `POSTGRES_PASSWORD` and `DB_PASSWORD` (same value) when using
            `sops.placeholder` for the DB secret; then set `postgres.password` to empty.
          '';
        };

        postgres = {
          image = mkOption {
            type = types.str;
            default = "ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0@sha256:bcf63357191b76a916ae5eb93464d65c07511da41e3bf7a8416db519b40b1c23";
            description = "Immich recommended Postgres image with vector extensions.";
          };

          user = mkOption {
            type = types.str;
            default = "postgres";
            description = "Immich Postgres username.";
          };

          password = mkOption {
            type = types.str;
            default = "";
            description = ''
              Immich Postgres password (inline `POSTGRES_PASSWORD` / `DB_PASSWORD`).
              Leave empty when using `environmentFiles` with those keys from a sops template.
            '';
          };

          database = mkOption {
            type = types.str;
            default = "immich";
            description = "Immich Postgres database name.";
          };
        };
      };

      config = lib.mkIf cfg.enable {
        assertions = [
          {
            assertion =
              cfg.postgres.password != "" || cfg.environmentFiles != [ ];
            message =
              "chiasson.system.services.immich: set postgres.password or environmentFiles (e.g. sops-rendered POSTGRES_PASSWORD + DB_PASSWORD).";
          }
        ];

        virtualisation = {
          docker.enable = true;
          oci-containers = {
            backend = "docker";
            containers = {
              immich-redis = {
                image = "docker.io/valkey/valkey:9@sha256:3b55fbaa0cd93cf0d9d961f405e4dfcc70efe325e2d84da207a0a8e6d8fde4f9";
                extraOptions = [ "--network=immich-network" ];
              };

              immich-database = {
                image = cfg.postgres.image;
                environment =
                  {
                    POSTGRES_USER = cfg.postgres.user;
                    POSTGRES_DB = cfg.postgres.database;
                    POSTGRES_INITDB_ARGS = "--data-checksums";
                  }
                  // lib.optionalAttrs (cfg.postgres.password != "") {
                    POSTGRES_PASSWORD = cfg.postgres.password;
                  };
                environmentFiles = cfg.environmentFiles;
                volumes = [ "immich-postgres:/var/lib/postgresql/data" ];
                extraOptions = [
                  "--network=immich-network"
                  "--shm-size=128mb"
                ];
              };

              immich-machine-learning = {
                image = "ghcr.io/immich-app/immich-machine-learning:${cfg.version}";
                environment = {
                  TZ = cfg.timezone;
                };
                volumes = [ "immich-model-cache:/cache" ];
                extraOptions = [ "--network=immich-network" ];
              };

              immich-server = {
                image = "ghcr.io/immich-app/immich-server:${cfg.version}";
                dependsOn = [
                  "immich-redis"
                  "immich-database"
                  "immich-machine-learning"
                ];
                ports = [ "${cfg.host}:${toString cfg.port}:2283" ];
                environment =
                  {
                    TZ = cfg.timezone;
                    DB_HOSTNAME = "immich-database";
                    DB_USERNAME = cfg.postgres.user;
                    DB_DATABASE_NAME = cfg.postgres.database;
                    REDIS_HOSTNAME = "immich-redis";
                    IMMICH_MACHINE_LEARNING_URL = "http://immich-machine-learning:3003";
                    UPLOAD_LOCATION = "/data";
                  }
                  // lib.optionalAttrs (cfg.postgres.password != "") { DB_PASSWORD = cfg.postgres.password; };
                environmentFiles = cfg.environmentFiles;
                volumes = [
                  "${cfg.uploadLocation}:/data"
                  "/etc/localtime:/etc/localtime:ro"
                ];
                extraOptions = [
                  "--network=immich-network"
                  "--pull=always"
                ];
              };
            };
          };
        };

        systemd.services.immich-network = {
          description = "Create Docker network for Immich";
          after = [ "docker.service" ];
          requires = [ "docker.service" ];
          wantedBy = [ "multi-user.target" ];
          serviceConfig.Type = "oneshot";
          script = ''
            ${pkgs.docker}/bin/docker network inspect immich-network >/dev/null 2>&1 || \
            ${pkgs.docker}/bin/docker network create immich-network
          '';
        };

        systemd.services."docker-immich-redis" = {
          after = [ "immich-network.service" ];
          requires = [ "immich-network.service" ];
        };

        systemd.services."docker-immich-database" = {
          after = [ "immich-network.service" ];
          requires = [ "immich-network.service" ];
        };

        systemd.services."docker-immich-machine-learning" = {
          after = [ "immich-network.service" ];
          requires = [ "immich-network.service" ];
        };

        systemd.services."docker-immich-server" = {
          after = [
            "immich-network.service"
            "docker-immich-redis.service"
            "docker-immich-database.service"
            "docker-immich-machine-learning.service"
          ];
          requires = [
            "immich-network.service"
            "docker-immich-redis.service"
            "docker-immich-database.service"
            "docker-immich-machine-learning.service"
          ];
        };

        networking.firewall.allowedTCPPorts = lib.optionals cfg.openFirewall [ cfg.port ];
      };
    };
}
