#!/usr/bin/env bash
set -uo pipefail

export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:${PATH:-}"

ROOT_DIR="${INSTALL_ROOT:-/opt/nvr}"
GATEWAY_DIR="${GATEWAY_DIR:-$ROOT_DIR/gateway}"

env_file_get() {
  local key="$1"
  local file="$GATEWAY_DIR/.env"
  local line value

  [ -r "$file" ] || return 1
  line="$(grep -m1 -E "^${key}=" "$file" 2>/dev/null || true)"
  [ -n "$line" ] || return 1
  value="${line#*=}"
  value="${value%\"}"
  value="${value#\"}"
  value="${value%\'}"
  value="${value#\'}"
  printf '%s' "$value"
}

LOCAL_WEB_PORT="${LOCAL_WEB_PORT:-$(env_file_get LOCAL_WEB_PORT || true)}"
LOCAL_WEB_PORT="${LOCAL_WEB_PORT:-9080}"

mask_stream() {
  sed -E \
    -e 's/(gateway_token|api_token|token|password|secret|app_key|shared_secret)([[:space:]]*[:=][[:space:]]*)"?[^",[:space:]]+"?/\1\2<redacted>/Ig' \
    -e 's/("(gateway_token|api_token|token|password|secret|app_key|shared_secret)"[[:space:]]*:[[:space:]]*")[^"]+/\1<redacted>/Ig' \
    -e 's/("(gateway_id|license_id)"[[:space:]]*:[[:space:]]*")[^"]+/\1<redacted>/Ig' \
    -e 's/("(gateway_code)"[[:space:]]*:[[:space:]]*")[^"]+/\1<redacted>/Ig' \
    -e 's/([A-Z0-9._%+-]+)@([A-Z0-9.-]+\.[A-Z]{2,})/<email-redacted>/Ig'
}

if [ "${NVR_RECONCILE_TEE:-0}" != "1" ]; then
  export NVR_RECONCILE_TEE=1
  PUBLIC_DIAG_PATH="${PUBLIC_DIAG_PATH:-$ROOT_DIR/platform/public/nvr-gateway-diag-20260612.txt}"
  STORAGE_DIAG_PATH="${STORAGE_DIAG_PATH:-$ROOT_DIR/platform/storage/app/public/nvr-gateway-diag-20260612.txt}"
  LOG_TMP="$(mktemp)"
  set +e
  bash "$0" "$@" 2>&1 | tee "$LOG_TMP"
  status="${PIPESTATUS[0]}"
  if [ -d "$(dirname "$PUBLIC_DIAG_PATH")" ]; then
    mask_stream <"$LOG_TMP" >"$PUBLIC_DIAG_PATH" 2>/dev/null || true
    chmod 0644 "$PUBLIC_DIAG_PATH" 2>/dev/null || true
    printf 'public_diag_url=/nvr/%s\n' "$(basename "$PUBLIC_DIAG_PATH")"
  fi
  if [ -d "$(dirname "$STORAGE_DIAG_PATH")" ]; then
    mask_stream <"$LOG_TMP" >"$STORAGE_DIAG_PATH" 2>/dev/null || true
    chmod 0644 "$STORAGE_DIAG_PATH" 2>/dev/null || true
    printf 'storage_diag_url=/nvr/storage/%s\n' "$(basename "$STORAGE_DIAG_PATH")"
  fi
  rm -f "$LOG_TMP"
  exit "$status"
fi

print_kv() {
  printf '%s=%s\n' "$1" "$2"
}

service_user() {
  local user
  user="$(systemctl show -p User --value gateway-daemon.service 2>/dev/null || true)"
  if [ -n "$user" ] && id "$user" >/dev/null 2>&1; then
    printf '%s' "$user"
    return 0
  fi

  for user in www-data nvr; do
    if id "$user" >/dev/null 2>&1; then
      printf '%s' "$user"
      return 0
    fi
  done

  printf 'root'
}

service_group() {
  local group="$1"
  local unit_group

  unit_group="$(systemctl show -p Group --value gateway-daemon.service 2>/dev/null || true)"
  if [ -n "$unit_group" ] && getent group "$unit_group" >/dev/null 2>&1; then
    printf '%s' "$unit_group"
    return 0
  fi

  id -gn "$group" 2>/dev/null || printf '%s' "$group"
}

gateway_storage_root() {
  local storage_root
  storage_root="$(env_file_get STORAGE_ROOT || true)"
  storage_root="${storage_root:-/var/lib/nvr}"

  if [ "${storage_root#/}" = "$storage_root" ]; then
    storage_root="$GATEWAY_DIR/${storage_root#./}"
  fi

  printf '%s' "$storage_root"
}

ensure_runtime_permissions() {
  local user="$1"
  local group="$2"
  local storage_root="$3"
  local dir child

  [ -n "$storage_root" ] || return 0
  install -d -o "$user" -g "$group" -m 2770 "$storage_root" 2>/dev/null || true

  for child in logs cache recordings snapshots tmp database run pids; do
    dir="$storage_root/$child"
    install -d -o "$user" -g "$group" -m 2770 "$dir" 2>/dev/null || true
    chown -R "$user:$group" "$dir" 2>/dev/null || true
    chmod -R u+rwX,g+rwX,o-rwx "$dir" 2>/dev/null || true
  done

  print_kv runtime_permissions ensured
  print_kv runtime_storage_root "$storage_root"
}

run_as_service_user() {
  local user="$1"
  shift

  if [ "$user" = "root" ]; then
    env GATEWAY_ENV_FILE_AUTHORITATIVE=1 \
      GATEWAY_BOOTSTRAP_VALIDATE_ON_BOOT=false \
      GATEWAY_VALIDATE_ON_BOOT=false \
      "$@"
    return $?
  fi

  if command -v runuser >/dev/null 2>&1; then
    runuser -u "$user" -- env GATEWAY_ENV_FILE_AUTHORITATIVE=1 \
      GATEWAY_BOOTSTRAP_VALIDATE_ON_BOOT=false \
      GATEWAY_VALIDATE_ON_BOOT=false \
      "$@"
    return $?
  fi

  su -s /bin/sh "$user" -c "GATEWAY_ENV_FILE_AUTHORITATIVE=1 GATEWAY_BOOTSTRAP_VALIDATE_ON_BOOT=false GATEWAY_VALIDATE_ON_BOOT=false $(printf '%q ' "$@")"
}

http_probe() {
  local name="$1"
  local url="$2"
  local body_file status

  body_file="$(mktemp)"
  status="$(curl -sS --max-time 8 -o "$body_file" -w "%{http_code}" "$url" 2>/dev/null || true)"
  print_kv "${name}_http" "${status:-000}"
  if [ -s "$body_file" ]; then
    printf '%s_body=' "$name"
    tr '\r\n' '  ' <"$body_file" | cut -c 1-500 | mask_stream
    printf '\n'
  fi
  rm -f "$body_file"
}

set_env_value() {
  local key="$1"
  local value="$2"
  local file="$GATEWAY_DIR/.env"

  [ -f "$file" ] || return 1
  if grep -q -E "^${key}=" "$file" 2>/dev/null; then
    sed -i -E "s#^${key}=.*#${key}=${value}#" "$file"
  else
    printf '%s=%s\n' "$key" "$value" >>"$file"
  fi
}

ensure_platform_base_url() {
  local current fixed

  current="$(env_file_get PLATFORM_BASE_URL || true)"
  fixed="http://127.0.0.1/nvr"

  case "$current" in
    ""|"http://127.0.0.1:8080"|"http://localhost:8080"|"http://127.0.0.1"|"http://localhost")
      if set_env_value PLATFORM_BASE_URL "$fixed"; then
        print_kv platform_base_url corrected_to_local_nvr
      else
        print_kv platform_base_url correction_failed
      fi
      ;;
    *)
      print_kv platform_base_url already_configured
      ;;
  esac
}

state_json_value() {
  local key="$1"
  local state_file="$GATEWAY_DIR/storage/cache/gateway-state.json"

  [ -s "$state_file" ] || return 1
  php -r '
    $state = json_decode((string) file_get_contents($argv[1]), true) ?: [];
    $key = (string) $argv[2];
    $value = $state[$key] ?? "";
    if (is_scalar($value)) {
        echo (string) $value;
    }
  ' "$state_file" "$key" 2>/dev/null
}

ensure_gateway_identity_config() {
  local state_gateway_id current_gateway_id state_gateway_code current_gateway_code

  state_gateway_id="$(state_json_value gateway_id || true)"
  state_gateway_code="$(state_json_value gateway_code || true)"
  current_gateway_id="$(env_file_get GATEWAY_ID || true)"
  current_gateway_code="$(env_file_get GATEWAY_CODE || true)"

  if [ -n "$state_gateway_id" ]; then
    if [ -z "$current_gateway_id" ] || [ "$current_gateway_id" = "gateway-local-001" ] || [ "$current_gateway_id" != "$state_gateway_id" ]; then
      if set_env_value GATEWAY_ID "$state_gateway_id"; then
        print_kv gateway_id_config synced_from_state
      else
        print_kv gateway_id_config sync_failed
      fi
    else
      print_kv gateway_id_config already_matches_state
    fi
  else
    print_kv gateway_id_config state_missing
  fi

  if [ -n "$state_gateway_code" ]; then
    if [ -z "$current_gateway_code" ] || [ "$current_gateway_code" != "$state_gateway_code" ]; then
      if set_env_value GATEWAY_CODE "$state_gateway_code"; then
        print_kv gateway_code_config synced_from_state
      else
        print_kv gateway_code_config sync_failed
      fi
    else
      print_kv gateway_code_config already_matches_state
    fi
  fi
}

materialize_local_platform_contract() {
  local platform_env="$ROOT_DIR/platform/.env"
  local state_file="$GATEWAY_DIR/storage/cache/gateway-state.json"

  if [ ! -s "$state_file" ]; then
    print_kv local_contract_materialize skipped_missing_state
    return 0
  fi

  if [ ! -r "$platform_env" ]; then
    print_kv local_contract_materialize skipped_missing_platform_env
    return 0
  fi

  local php_script
  php_script="$(mktemp)"
  cat >"$php_script" <<'PHP'
<?php
declare(strict_types=1);

$platformEnv = $argv[1];
$stateFile = $argv[2];

$parseEnv = static function (string $path): array {
    $env = [];
    foreach (file($path, FILE_IGNORE_NEW_LINES) ?: [] as $line) {
        $trimmed = trim($line);
        if ($trimmed === '' || str_starts_with($trimmed, '#') || ! str_contains($line, '=')) {
            continue;
        }
        [$key, $value] = explode('=', $line, 2);
        $value = trim($value);
        if ((str_starts_with($value, '"') && str_ends_with($value, '"')) || (str_starts_with($value, "'") && str_ends_with($value, "'"))) {
            $value = substr($value, 1, -1);
        }
        $env[trim($key)] = str_replace(['\\n', '\\r', '\\"'], ["\n", "\r", '"'], $value);
    }
    return $env;
};

$first = static function (array $values): string {
    foreach ($values as $value) {
        if (! is_scalar($value) && $value !== null) {
            continue;
        }
        $value = trim((string) $value);
        if ($value !== '') {
            return $value;
        }
    }
    return '';
};

$bool = static fn (mixed $value): bool => filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE) ?? (bool) $value;
$uuid = static function (): string {
    $data = random_bytes(16);
    $data[6] = chr((ord($data[6]) & 0x0f) | 0x40);
    $data[8] = chr((ord($data[8]) & 0x3f) | 0x80);
    return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4));
};
$tableExists = static function (PDO $pdo, string $table): bool {
    $stmt = $pdo->prepare('SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = ?');
    $stmt->execute([$table]);
    return (int) $stmt->fetchColumn() > 0;
};

$env = $parseEnv($platformEnv);
$state = json_decode((string) file_get_contents($stateFile), true);
if (! is_array($state)) {
    echo "local_contract_materialize=skipped_invalid_state\n";
    exit(0);
}

$license = is_array($state['license'] ?? null) ? $state['license'] : [];
$client = is_array($state['client'] ?? null) ? $state['client'] : [];
$site = is_array($state['site'] ?? null) ? $state['site'] : [];

$gatewayId = $first([$state['gateway_id'] ?? null]);
$gatewayCode = $first([$state['gateway_code'] ?? null, $state['codigo'] ?? null]);
$gatewayToken = $first([$state['gateway_token'] ?? null]);
$tenantId = $first([getenv('NVR_RECOVERY_TENANT_ID') ?: null, $state['tenant_id'] ?? null, $state['client_id'] ?? null, $state['cliente_id'] ?? null, $client['id'] ?? null, $license['tenant_id'] ?? null, $license['client_id'] ?? null, $license['cliente_id'] ?? null]);

if ($gatewayId === '' || $gatewayCode === '' || $gatewayToken === '' || $tenantId === '') {
    echo "local_contract_materialize=skipped_missing_contract\n";
    echo "local_contract_gateway_id_present=" . ($gatewayId !== '' ? 'true' : 'false') . "\n";
    echo "local_contract_gateway_code_present=" . ($gatewayCode !== '' ? 'true' : 'false') . "\n";
    echo "local_contract_gateway_token_present=" . ($gatewayToken !== '' ? 'true' : 'false') . "\n";
    echo "local_contract_tenant_present=" . ($tenantId !== '' ? 'true' : 'false') . "\n";
    exit(0);
}

$dbHost = $env['DB_HOST'] ?? '127.0.0.1';
$dbPort = $env['DB_PORT'] ?? '3306';
$dbName = $env['DB_DATABASE'] ?? '';
$dbUser = $env['DB_USERNAME'] ?? '';
$dbPass = $env['DB_PASSWORD'] ?? '';
if ($dbName === '' || $dbUser === '') {
    echo "local_contract_materialize=skipped_missing_db_env\n";
    exit(0);
}

$pdo = new PDO("mysql:host={$dbHost};port={$dbPort};dbname={$dbName};charset=utf8mb4", $dbUser, $dbPass, [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]);

$tables = [];
foreach (['gateways', 'gateway_activations', 'gateway_heartbeats', 'licenses', 'license_events'] as $logical) {
    $prefixed = 'nvr_' . $logical;
    $tables[$logical] = $tableExists($pdo, $prefixed) ? $prefixed : $logical;
}

$tenantCode = substr($first([getenv('NVR_RECOVERY_TENANT_CODE') ?: null, $client['codigo'] ?? null, $client['code'] ?? null, 'central-' . substr(str_replace('-', '', $tenantId), 0, 12)]), 0, 32);
$tenantName = substr($first([getenv('NVR_RECOVERY_TENANT_NAME') ?: null, $client['nome_fantasia'] ?? null, $client['name'] ?? null, $client['razao_social'] ?? null, 'Cliente NVR ' . substr($tenantId, 0, 8)]), 0, 150);
$tenantEmail = $first([getenv('NVR_RECOVERY_TENANT_EMAIL') ?: null, $client['email_principal'] ?? null, $client['email'] ?? null, 'nvr-' . substr(str_replace('-', '', $tenantId), 0, 12) . '@nvr.invalid']);
$siteId = $first([$state['site_id'] ?? null, $site['id'] ?? null, $license['site_id'] ?? null]);
$activationCode = strtoupper($first([getenv('NVR_RECOVERY_ACTIVATION_CODE') ?: null, $state['activation_code'] ?? null]));
$activationPrefix = $activationCode !== '' ? substr($activationCode, 0, 12) : substr($gatewayCode, 0, 12);
$licenseId = $first([getenv('NVR_RECOVERY_LICENSE_ID') ?: null, $license['id'] ?? null, $license['license_id'] ?? null, $uuid()]);
$licenseKey = $first([getenv('NVR_RECOVERY_LICENSE_KEY') ?: null, $license['license_key'] ?? null, $license['key'] ?? null, 'CENTRAL-' . strtoupper(substr(preg_replace('/[^A-Za-z0-9]/', '', $gatewayCode) ?: 'NVR', 0, 32))]);
$licenseStatus = $first([$license['status'] ?? null, 'ativo']);
$remoteAllowed = $bool($state['remote_access_allowed'] ?? $license['remote_access_allowed'] ?? true);
$localAllowed = $bool($state['local_recording_allowed'] ?? $license['local_operation_allowed'] ?? true);
$now = gmdate('Y-m-d H:i:s.u');

$pdo->beginTransaction();
try {
    $stmt = $pdo->prepare("INSERT INTO clientes (id, codigo, tipo_cliente, nome_fantasia, email_principal, status, data_ativacao, metadata, created_at, updated_at)
        VALUES (:id, :codigo, 'empresa', :nome, :email, 'ativo', UTC_TIMESTAMP(6), :metadata, UTC_TIMESTAMP(6), UTC_TIMESTAMP(6))
        ON DUPLICATE KEY UPDATE nome_fantasia = VALUES(nome_fantasia), status = 'ativo', updated_at = UTC_TIMESTAMP(6)");
    $stmt->execute([
        'id' => $tenantId,
        'codigo' => $tenantCode,
        'nome' => $tenantName,
        'email' => $tenantEmail,
        'metadata' => json_encode(['source' => 'gateway_reconcile', 'central_contract_imported' => true], JSON_UNESCAPED_SLASHES),
    ]);

    $gatewayTable = $tables['gateways'];
    $stmt = $pdo->prepare("INSERT INTO `{$gatewayTable}` (id, cliente_id, site_id, codigo, nome, status, appliance_uid, activation_code_hash, activation_code_prefix, api_token_hash, ip_local, remote_access_enabled, local_recording_enabled, connectivity_status, recording_status, activated_at, last_heartbeat_at, metadata, created_at, updated_at)
        VALUES (:id, :cliente_id, :site_id, :codigo, :nome, 'ativo', :appliance_uid, :activation_code_hash, :activation_code_prefix, :api_token_hash, :ip_local, :remote_access_enabled, :local_recording_enabled, 'online', 'ok', UTC_TIMESTAMP(6), UTC_TIMESTAMP(6), :metadata, UTC_TIMESTAMP(6), UTC_TIMESTAMP(6))
        ON DUPLICATE KEY UPDATE cliente_id = VALUES(cliente_id), site_id = VALUES(site_id), nome = VALUES(nome), status = 'ativo', activation_code_prefix = VALUES(activation_code_prefix), api_token_hash = VALUES(api_token_hash), ip_local = COALESCE(VALUES(ip_local), ip_local), remote_access_enabled = VALUES(remote_access_enabled), local_recording_enabled = VALUES(local_recording_enabled), connectivity_status = 'online', recording_status = 'ok', activated_at = COALESCE(activated_at, UTC_TIMESTAMP(6)), last_heartbeat_at = UTC_TIMESTAMP(6), metadata = VALUES(metadata), updated_at = UTC_TIMESTAMP(6)");
    $stmt->execute([
        'id' => $gatewayId,
        'cliente_id' => $tenantId,
        'site_id' => $siteId !== '' ? $siteId : null,
        'codigo' => $gatewayCode,
        'nome' => $first([$state['gateway_name'] ?? null, 'Gateway ' . strtoupper(substr($gatewayCode, 0, 24))]),
        'appliance_uid' => $first([$state['appliance_uid'] ?? null]) ?: null,
        'activation_code_hash' => $activationCode !== '' ? hash('sha256', $activationCode) : null,
        'activation_code_prefix' => $activationPrefix,
        'api_token_hash' => hash('sha256', $gatewayToken),
        'ip_local' => $first([$state['ip_local'] ?? null]) ?: null,
        'remote_access_enabled' => $remoteAllowed ? 1 : 0,
        'local_recording_enabled' => $localAllowed ? 1 : 0,
        'metadata' => json_encode(['source' => 'gateway_reconcile', 'central_contract_persisted' => true, 'product_code' => $license['product_code'] ?? 'nvr'], JSON_UNESCAPED_SLASHES),
    ]);

    $licenseTable = $tables['licenses'];
    $stmt = $pdo->prepare("INSERT INTO `{$licenseTable}` (id, gateway_id, cliente_id, site_id, license_key, status, starts_at, ends_at, grace_period_ends_at, metadata, created_at, updated_at)
        VALUES (:id, :gateway_id, :cliente_id, :site_id, :license_key, :status, UTC_TIMESTAMP(6), :ends_at, :grace_period_ends_at, :metadata, UTC_TIMESTAMP(6), UTC_TIMESTAMP(6))
        ON DUPLICATE KEY UPDATE cliente_id = VALUES(cliente_id), site_id = VALUES(site_id), status = VALUES(status), ends_at = VALUES(ends_at), grace_period_ends_at = VALUES(grace_period_ends_at), metadata = VALUES(metadata), updated_at = UTC_TIMESTAMP(6)");
    $stmt->execute([
        'id' => $licenseId,
        'gateway_id' => $gatewayId,
        'cliente_id' => $tenantId,
        'site_id' => $siteId !== '' ? $siteId : null,
        'license_key' => $licenseKey,
        'status' => $licenseStatus,
        'ends_at' => $first([$license['ends_at'] ?? null]) ?: null,
        'grace_period_ends_at' => $first([$license['grace_period_ends_at'] ?? null]) ?: null,
        'metadata' => json_encode(['source' => 'gateway_reconcile', 'remote_access_allowed' => $remoteAllowed, 'local_operation_allowed' => $localAllowed, 'product_code' => $license['product_code'] ?? 'nvr'], JSON_UNESCAPED_SLASHES),
    ]);

    $activationTable = $tables['gateway_activations'];
    $stmt = $pdo->prepare("INSERT INTO `{$activationTable}` (id, gateway_id, status, activation_code_prefix, appliance_uid, hostname, ip_local, activated_at, expires_at, metadata, created_at, updated_at)
        VALUES (:id, :gateway_id, 'ativado', :activation_code_prefix, :appliance_uid, :hostname, :ip_local, UTC_TIMESTAMP(6), NULL, :metadata, UTC_TIMESTAMP(6), UTC_TIMESTAMP(6))");
    $stmt->execute([
        'id' => $uuid(),
        'gateway_id' => $gatewayId,
        'activation_code_prefix' => $activationPrefix,
        'appliance_uid' => $first([$state['appliance_uid'] ?? null]) ?: null,
        'hostname' => gethostname() ?: null,
        'ip_local' => $first([$state['ip_local'] ?? null]) ?: null,
        'metadata' => json_encode(['source' => 'gateway_reconcile'], JSON_UNESCAPED_SLASHES),
    ]);

    $pdo->commit();
    echo "local_contract_materialize=ok\n";
    echo "local_contract_gateway_present=true\n";
    echo "local_contract_license_status={$licenseStatus}\n";
} catch (Throwable $exception) {
    $pdo->rollBack();
    echo "local_contract_materialize=failed\n";
    echo "local_contract_error=" . preg_replace('/\s+/', ' ', $exception->getMessage()) . "\n";
}
PHP

  if ! NVR_RECOVERY_TENANT_ID="${NVR_RECOVERY_TENANT_ID:-}" \
    NVR_RECOVERY_TENANT_CODE="${NVR_RECOVERY_TENANT_CODE:-}" \
    NVR_RECOVERY_TENANT_NAME="${NVR_RECOVERY_TENANT_NAME:-}" \
    NVR_RECOVERY_TENANT_EMAIL="${NVR_RECOVERY_TENANT_EMAIL:-}" \
    NVR_RECOVERY_LICENSE_ID="${NVR_RECOVERY_LICENSE_ID:-}" \
    NVR_RECOVERY_LICENSE_KEY="${NVR_RECOVERY_LICENSE_KEY:-}" \
    NVR_RECOVERY_ACTIVATION_CODE="${NVR_RECOVERY_ACTIVATION_CODE:-}" \
    php "$php_script" "$platform_env" "$state_file" 2>&1 | mask_stream; then
    print_kv local_contract_materialize_php failed
  fi
  rm -f "$php_script"
}

print_kv reconcile_start "$(date -Is 2>/dev/null || date)"
print_kv root_dir "$ROOT_DIR"
print_kv gateway_dir "$GATEWAY_DIR"
print_kv local_web_port "$LOCAL_WEB_PORT"

if [ ! -x "$GATEWAY_DIR/bin/gateway" ]; then
  print_kv gateway_cli missing
  exit 1
fi

ensure_platform_base_url
ensure_gateway_identity_config
materialize_local_platform_contract

USER_NAME="$(service_user)"
GROUP_NAME="$(service_group "$USER_NAME")"
print_kv service_user "$USER_NAME"
print_kv service_group "$GROUP_NAME"
ensure_runtime_permissions "$USER_NAME" "$GROUP_NAME" "$(gateway_storage_root)"

if [ -d "$GATEWAY_DIR/storage" ] && [ "$USER_NAME" != "root" ]; then
  chown -R "$USER_NAME:$GROUP_NAME" "$GATEWAY_DIR/storage" 2>/dev/null || true
fi

systemctl daemon-reload 2>/dev/null || true
for unit in gateway-bootstrap.service gateway-daemon.service gateway-local-web.service nvr-gateway.target; do
  systemctl reset-failed "$unit" 2>/dev/null || true
done

systemctl restart gateway-bootstrap.service 2>/dev/null || true
systemctl restart gateway-daemon.service gateway-local-web.service 2>/dev/null || true
sleep 3

for unit in gateway-bootstrap.service gateway-daemon.service gateway-local-web.service nvr-gateway.target; do
  if systemctl is-active --quiet "$unit" 2>/dev/null; then
    print_kv "unit_${unit%.service}" active
  else
    print_kv "unit_${unit%.service}" inactive
  fi
done

cd "$GATEWAY_DIR" || exit 1

print_kv bootstrap_run start
if run_as_service_user "$USER_NAME" php bin/gateway app:bootstrap 2>&1 | mask_stream; then
  print_kv bootstrap_result ok
else
  print_kv bootstrap_result failed
fi

print_kv status_run start
if run_as_service_user "$USER_NAME" php bin/gateway gateway:status 2>&1 | mask_stream | sed -E 's/"(gateway_id|gateway_code)"[[:space:]]*:[[:space:]]*"[^"]+"/"\1":"<set>"/g'; then
  print_kv status_result ok
else
  print_kv status_result failed
fi

print_kv heartbeat_run start
if run_as_service_user "$USER_NAME" php bin/gateway gateway:heartbeat 2>&1 | mask_stream; then
  print_kv heartbeat_result ok
else
  print_kv heartbeat_result failed
fi

systemctl restart gateway-daemon.service gateway-local-web.service 2>/dev/null || true
sleep 3

http_probe gateway_livez "http://127.0.0.1:${LOCAL_WEB_PORT}/livez"
http_probe gateway_readyz "http://127.0.0.1:${LOCAL_WEB_PORT}/readyz"
http_probe nvr_healthz "http://127.0.0.1/nvr/healthz"

if [ -s "$GATEWAY_DIR/storage/cache/gateway-state.json" ]; then
  print_kv gateway_state_file present
  php -r '
    $state = json_decode((string) file_get_contents($argv[1]), true) ?: [];
    $license = is_array($state["license"] ?? null) ? $state["license"] : [];
    echo "gateway_state_registered=" . (!empty($state["registered"]) ? "true" : "false") . PHP_EOL;
    echo "gateway_state_token_present=" . (!empty($state["gateway_token"]) ? "true" : "false") . PHP_EOL;
    echo "gateway_state_license_status=" . (string) ($license["status"] ?? "unknown") . PHP_EOL;
    echo "gateway_state_last_heartbeat=" . (string) ($state["last_heartbeat_at"] ?? "NULL") . PHP_EOL;
  ' "$GATEWAY_DIR/storage/cache/gateway-state.json" 2>/dev/null | mask_stream || true
else
  print_kv gateway_state_file missing
fi

print_kv reconcile_done ok
