{ inputs, flake, self }:
{ config, pkgs, lib, ... }: let 
  cfg = config.hectic.marzban;
in {
  options = {
    hectic.marzban = {
      enable = lib.mkEnableOption "Enable marzban";
      environment = lib.mkOption {
        type = lib.types.attrs;
        default = {};
        description = "The environment variables to set for the marzban service.";
      };
      marzbanPackage = lib.mkOption {
        type = lib.types.package;
        default = null;
        defaultText = "pkgs.hectic.marzban-cli";
        description = "The marzban-cli package to use.";
      };
      settings = lib.mkOption {
        type = lib.types.nullOr (lib.types.attrsOf lib.types.unspecified);
        default = null;
        example = {
          inbounds = [
            {
              port = 1080;
              listen = "127.0.0.1";
              protocol = "http";
            }
          ];
          outbounds = [
            {
              protocol = "freedom";
            }
          ];
        };
        description = ''
          The configuration object.

          Either `settingsFile` or `settings` must be specified.

          See <https://www.v2fly.org/en_US/config/overview.html>.
        '';
      };
    };
  };
  config = lib.mkIf cfg.enable (let

    databaseUrl = "${cfg.environment.POSTGRES_USER}:${cfg.environment.POSTGRES_PASSWORD}@${cfg.environment.DB_HOST}:${cfg.environment.DB_PORT}/marzban";
    # Sync URL for both main application and alembic migrations
    syncDatabaseUrl = "postgresql+asyncpg://${databaseUrl}";
    
    marzbanEnvironment = {
      PYTHONPATH = "${cfg.marzbanPackage}/lib/marzban";
      SQLALCHEMY_DATABASE_URL = syncDatabaseUrl;
      XRAY_JSON = "${pkgs.writeText "xray_config.json" (builtins.toJSON cfg.settings)}";
      XRAY_EXECUTABLE_PATH = "${pkgs.xray}/bin/xray";
      XRAY_ASSETS_PATH = "${pkgs.xray}/share/xray";
    };
    
    alembicEnvironment = marzbanEnvironment;
    
    environmentExports = lib.concatStringsSep "\n" (lib.mapAttrsToList (name: value: "export ${name}=${value}") marzbanEnvironment);
  in {
    services.postgresql = {
      enable = true;
      ensureDatabases = [ "marzban" ];
      # NOTICE(yukkop): own user and md5 hash pass
    };

    services.xray = {
      enable = true;
      package = pkgs.xray;
      settings = cfg.settings;
    };

    systemd.services.marzban = {
      enable = true;
      after = [ "postgresql.service" "xray.service" ];
      requires = [ "postgresql.service" "xray.service" ];
      wantedBy = [ "multi-user.target" ];
      serviceConfig = {
        WorkingDirectory = "${cfg.marzbanPackage}/lib/marzban";
        ExecStartPre = let
          python = "${cfg.marzbanPackage}/bin/python";
          alembic = "${python} -m alembic";
        in "${pkgs.writeScript "alembic-upgrade" ''
          #!/bin/sh
          echo "NOTICE: Upgrading database..."
          echo "DEBUG: Current environment:"
          env | grep -E 'POSTGRES|SQL|DB_'
          ${lib.concatStringsSep "\n" (lib.mapAttrsToList (name: value: "export ${name}=${value}") alembicEnvironment)}
          echo "DEBUG: After setting environment:"
          env | grep -E 'POSTGRES|SQL|DB_'
          ${lib.concatStringsSep "\n" (lib.mapAttrsToList (name: value: "export ${name}=${value}") alembicEnvironment)}
          ${alembic} upgrade head
          echo "NOTICE: Database upgraded"
        ''}";
        ExecStart = "${cfg.marzbanPackage}/bin/marzban";
      };
      environment = marzbanEnvironment;
    };

    environment.systemPackages = [
      pkgs.xray
      (pkgs.writeScriptBin "marzban-cli" ''
        ${environmentExports}

        ${cfg.marzbanPackage}/bin/marzban-cli
      '')
    ];
  });
}