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

provider_id="${1:?provider_id required}"
model_name="${2:?model_name required}"
env_var="${3:?env var required}"
key_file="${4:-}"

ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
# shellcheck disable=SC1091
source "$ROOT_DIR/scripts/acceptance/host_access_prep_lib.sh"
ARTIFACT_REDACTION_SCRIPT="$ROOT_DIR/scripts/acceptance/artifact_redaction.py"

KEY="${KEY:-/home/long/下载/zjsea.pem}"
REMOTE="${REMOTE:-ubuntu@43.155.133.187}"
CRM_BASE="${CRM_BASE:-http://127.0.0.1:18088}"
HOST_BASE="${HOST_BASE:-http://127.0.0.1:18087}"
CRM_HOST_BASE="${CRM_HOST_BASE:-$HOST_BASE}"
REMOTE_HOST_BASE="${REMOTE_HOST_BASE:-$CRM_HOST_BASE}"
HOST_NAME="${HOST_NAME:-remote43-current-host}"
REMOTE_HOST_ENV_FILE="${REMOTE_HOST_ENV_FILE:-/home/ubuntu/sub2api-host-validation-fresh-deepseek-20260519_115244/.env}"
REMOTE_PG_CONTAINER="${REMOTE_PG_CONTAINER:-}"
REMOTE_REDIS_CONTAINER="${REMOTE_REDIS_CONTAINER:-}"
PACK_PATH="${PACK_PATH:-$ROOT_DIR/packs/openai-cn-pack}"
REQUEST_PACK_PATH="${REQUEST_PACK_PATH:-$PACK_PATH}"
ROOT="${ROOT:-$ROOT_DIR/artifacts/real-host-acceptance}"
ART="${ART:-$ROOT/$(date +%Y%m%d_%H%M%S)_remote43_${provider_id}_key_import}"
MIN_BALANCE="${MIN_BALANCE:-10}"
SUBSCRIPTION_DAYS="${SUBSCRIPTION_DAYS:-30}"
SUBSCRIPTION_NOTES="${SUBSCRIPTION_NOTES:-hermes remote subscription validation}"
ARTIFACT_SECURITY_MODE="${ARTIFACT_SECURITY_MODE:-safe}"
ARTIFACT_INCLUDE_SECRETS="${ARTIFACT_INCLUDE_SECRETS:-0}"
CRM_COOKIE_JAR="${CRM_COOKIE_JAR:-}"
CRM_ADMIN_USERNAME="${CRM_ADMIN_USERNAME:-}"
CRM_ADMIN_PASSWORD="${CRM_ADMIN_PASSWORD:-}"
mkdir -p "$ART"

artifact_redact_key_json() {
  local value="$1"
  python3 "$ROOT_DIR/scripts/acceptance/artifact_redaction.py" redact-key "$value"
}

artifact_redact_id() {
  local value="$1"
  python3 "$ROOT_DIR/scripts/acceptance/artifact_redaction.py" redact-id "$value"
}

write_json_file() {
  local path="$1"
  local payload="$2"
  printf '%s\n' "$payload" > "$path"
}

sanitize_headers_file() {
  local path="$1"
  python3 "$ROOT_DIR/scripts/acceptance/artifact_redaction.py" sanitize-headers "$path" "$path"
}

sanitize_runtime_context_file() {
  local path="$1"
  local tmp="$path.tmp"
  python3 "$ROOT_DIR/scripts/acceptance/artifact_redaction.py" sanitize-runtime-context "$path" "$tmp"
  mv "$tmp" "$path"
}

sanitize_group_state_file() {
  local path="$1"
  local tmp="$path.tmp"
  python3 "$ROOT_DIR/scripts/acceptance/artifact_redaction.py" sanitize-group-state "$path" "$tmp"
  mv "$tmp" "$path"
}

redact_body_preview() {
  local text="$1"
  local value="$text"
  if [[ -n "${managed_probe_key:-}" ]]; then
    value="${value//$managed_probe_key/***}"
  fi
  if [[ -n "${upstream_key:-}" ]]; then
    value="${value//$upstream_key/***}"
  fi
  if [[ -n "${sub_key:-}" ]]; then
    value="${value//$sub_key/***}"
  fi
  printf '%s' "$value"
}

if [[ -n "$key_file" ]]; then
  upstream_key="$(tr -d '\r\n' < "$key_file")"
  key_source="file:$key_file"
else
  upstream_key="${!env_var:-}"
  key_source="env:$env_var"
fi
if [[ -z "$upstream_key" ]]; then
  echo "missing key from $key_source" >&2
  exit 2
fi

upstream_base_url="$(python3 - "$PACK_PATH" "$provider_id" <<'PY'
import json, pathlib, sys
pack_path = pathlib.Path(sys.argv[1])
provider_id = sys.argv[2]
provider_file = pack_path / "providers" / f"{provider_id}.json"
provider = json.loads(provider_file.read_text(encoding='utf-8'))
print(str(provider.get("base_url", "")).strip())
PY
)"
if [[ -z "$upstream_base_url" ]]; then
  echo "missing provider base_url for $provider_id in $PACK_PATH" >&2
  exit 2
fi

pack_id="$(python3 - "$PACK_PATH" <<'PY'
import json, pathlib, sys
pack_path = pathlib.Path(sys.argv[1])
pack_file = pack_path / "pack.json"
pack = json.loads(pack_file.read_text(encoding='utf-8'))
print(str(pack.get("pack_id", "")).strip())
PY
)"
if [[ -z "$pack_id" ]]; then
  echo "missing pack_id in $PACK_PATH/pack.json" >&2
  exit 2
fi

ssh_cmd() {
  local cmd="$1"
  ssh -i "$KEY" -o StrictHostKeyChecking=no "$REMOTE" "$cmd"
}

resolve_remote_host_runtime() {
  local remote_port host_containers
  remote_port="$(python3 - "$REMOTE_HOST_BASE" <<'PY'
from urllib.parse import urlparse
import sys

target = urlparse(sys.argv[1])
if target.port is not None:
    print(target.port)
elif target.scheme == 'https':
    print(443)
else:
    print(80)
PY
)"
  host_containers="$(ssh_cmd "sudo -n docker ps --format '{{.Names}}\t{{.Ports}}'")"
  HOST_CONTAINERS="$host_containers" python3 - "$remote_port" <<'PY'
import os
import sys

port = sys.argv[1]
rows = os.environ.get("HOST_CONTAINERS", "").splitlines()
for row in rows:
    name, _, ports = row.partition('\t')
    if f":{port}->" not in ports:
        continue
    app = name.strip()
    if app.endswith("-app-1"):
        prefix = app[:-len("-app-1")]
        print(app)
        print(f"{prefix}-postgres-1")
        print(f"{prefix}-redis-1")
        raise SystemExit(0)
    if app.endswith("-app"):
        prefix = app[:-len("-app")]
        print(app)
        print(f"{prefix}-pg")
        print(f"{prefix}-redis")
        raise SystemExit(0)
raise SystemExit(f"unable to derive target host containers from port {port}")
PY
}

if [[ -z "$REMOTE_PG_CONTAINER" || -z "$REMOTE_REDIS_CONTAINER" ]]; then
  mapfile -t resolved_remote_runtime < <(resolve_remote_host_runtime)
  if [[ ${#resolved_remote_runtime[@]} -lt 3 ]]; then
    echo "unable to resolve remote host runtime containers for $REMOTE_HOST_BASE" >&2
    exit 2
  fi
  REMOTE_PG_CONTAINER="${REMOTE_PG_CONTAINER:-${resolved_remote_runtime[1]}}"
  REMOTE_REDIS_CONTAINER="${REMOTE_REDIS_CONTAINER:-${resolved_remote_runtime[2]}}"
fi

REMOTE_PG_CONTAINER_Q="$(printf '%q' "$REMOTE_PG_CONTAINER")"
REMOTE_REDIS_CONTAINER_Q="$(printf '%q' "$REMOTE_REDIS_CONTAINER")"

build_managed_subscription_identity_json() {
  local selector="$1"
  local group_id="$2"
  python3 - "$selector" "$group_id" <<'PY'
import hashlib, json, sys

selector, group_id = sys.argv[1:3]

def sanitize(value: str) -> str:
    value = value.strip().lower()
    chars = []
    last_dash = False
    for ch in value:
        if ('a' <= ch <= 'z') or ('0' <= ch <= '9'):
            chars.append(ch)
            last_dash = False
        elif not last_dash:
            chars.append('-')
            last_dash = True
    return ''.join(chars).strip('-')

def truncate(value: str, max_len: int) -> str:
    if len(value) <= max_len:
        return value
    return value[:max_len].strip('-')

normalized = selector.strip().lower() + '|' + group_id.strip()
digest = hashlib.sha256(normalized.encode('utf-8')).hexdigest()
prefix = sanitize(selector) or 'relay-sub'
prefix = truncate(prefix, 24)
short_hash = digest[:16]
key_hash = digest[:32]
username = truncate(f"{prefix}-{short_hash[:8]}", 32)
print(json.dumps({
    'email': f"{prefix}-{short_hash}@sub2api.local",
    'username': username,
    'custom_key': 'sk-relay-' + key_hash,
    'key_name': truncate(username + '-key', 48),
}, ensure_ascii=False))
PY
}

remote_lookup_managed_subscription_user_id() {
  local email="$1"
  remote_pg_query "select id from users where email = $(sql_literal "$email") order by id desc limit 1;"
}

crm_curl_json() {
  local method="$1"
  local path="$2"
  local payload="${3:-}"
  local -a curl_args
  curl_args=(-fsS -X "$method")
  if [[ -n "${crm_token:-}" ]]; then
    curl_args+=(-H "Authorization: Bearer $crm_token")
  elif [[ -n "${crm_cookie_jar:-}" ]]; then
    curl_args+=(-b "$crm_cookie_jar" -c "$crm_cookie_jar")
  else
    echo "missing CRM auth: set CRM_ADMIN_TOKEN or CRM_COOKIE_JAR/CRM_ADMIN_USERNAME+CRM_ADMIN_PASSWORD" >&2
    exit 2
  fi
  if [[ -n "$payload" ]]; then
    curl_args+=(
      -H 'Content-Type: application/json'
      "${CRM_BASE}${path}"
      -d "$payload"
    )
  else
    curl_args+=("${CRM_BASE}${path}")
  fi
  curl "${curl_args[@]}"
}

crm_curl_capture() {
  local method="$1"
  local path="$2"
  local header_path="$3"
  local body_path="$4"
  local payload="${5:-}"
  local -a curl_args
  curl_args=(-sS -D "$header_path" -o "$body_path" -X "$method")
  if [[ -n "${crm_token:-}" ]]; then
    curl_args+=(-H "Authorization: Bearer $crm_token")
  elif [[ -n "${crm_cookie_jar:-}" ]]; then
    curl_args+=(-b "$crm_cookie_jar" -c "$crm_cookie_jar")
  else
    echo "missing CRM auth: set CRM_ADMIN_TOKEN or CRM_COOKIE_JAR/CRM_ADMIN_USERNAME+CRM_ADMIN_PASSWORD" >&2
    exit 2
  fi
  if [[ -n "$payload" ]]; then
    curl_args+=(
      -H 'Content-Type: application/json'
      "${CRM_BASE}${path}"
      -d "$payload"
    )
  else
    curl_args+=("${CRM_BASE}${path}")
  fi
  curl "${curl_args[@]}"
}

ensure_crm_session_cookie() {
  if [[ -n "$CRM_COOKIE_JAR" ]]; then
    crm_cookie_jar="$CRM_COOKIE_JAR"
  else
    crm_cookie_jar="/tmp/$(basename "$ART")-crm-cookie.jar"
  fi
  rm -f "$crm_cookie_jar"

  if [[ -z "$CRM_ADMIN_USERNAME" || -z "$CRM_ADMIN_PASSWORD" ]]; then
    echo "CRM admin username/password are required when CRM_ADMIN_TOKEN is unavailable" >&2
    exit 2
  fi

  local login_payload
  login_payload="$(python3 - "$CRM_ADMIN_USERNAME" "$CRM_ADMIN_PASSWORD" <<'PY'
import json, sys
username, password = sys.argv[1:3]
print(json.dumps({
  'username': username,
  'password': password,
}, ensure_ascii=False))
PY
)"

  curl -fsS -c "$crm_cookie_jar" -b "$crm_cookie_jar" \
    -H 'Content-Type: application/json' \
    -X POST \
    "${CRM_BASE}/api/admin/session/login" \
    -d "$login_payload" > /dev/null

  crm_curl_json GET "/api/admin/session" > /dev/null
}

fetch_remote_host_bearer_token() {
  ssh_cmd "python3 - <<'PY'
from pathlib import Path
import json, subprocess, sys

env_path = Path(${REMOTE_HOST_ENV_FILE@Q})
host_base = ${REMOTE_HOST_BASE@Q}
vals = {}
for line in env_path.read_text().splitlines():
    if '=' not in line:
        continue
    key, value = line.split('=', 1)
    vals[key] = value

payload = json.dumps({
    'email': vals['ADMIN_EMAIL'],
    'password': vals['ADMIN_PASSWORD'],
    'turnstile_token': '',
}, ensure_ascii=False)
res = subprocess.run([
    'curl', '-fsS', '-H', 'Content-Type: application/json', '-X', 'POST',
    host_base.rstrip('/') + '/api/v1/auth/login', '-d', payload,
], text=True, capture_output=True)
obj = json.loads(res.stdout)
token = (obj.get('data') or {}).get('access_token', '')
if not token:
    print(res.stdout, file=sys.stderr)
    raise SystemExit('missing access_token from remote host login')
print(token)
PY"
}

remote_pg_exec() {
  local sql="$1"
  local encoded
  encoded="$(printf '%s' "$sql" | base64 -w0)"
  ssh_cmd "printf '%s' '$encoded' | base64 -d | sudo -n docker exec -i $REMOTE_PG_CONTAINER_Q psql -U sub2api -d sub2api"
}

remote_pg_query() {
  local sql="$1"
  local encoded
  encoded="$(printf '%s' "$sql" | base64 -w0)"
  ssh_cmd "printf '%s' '$encoded' | base64 -d | sudo -n docker exec -i $REMOTE_PG_CONTAINER_Q psql -U sub2api -d sub2api -At -F $'\t'"
}

remote_fetch_group_state() {
  local group_id="$1"
  local user_id="$2"
  local api_key="$3"
  local output_path="$4"
  local sql
  sql="$(python3 - "$group_id" "$user_id" "$api_key" <<'PY'
import sys

group_id, user_id, api_key = sys.argv[1:4]
api_key_literal = "'" + api_key.replace("'", "''") + "'"
query = f"""
WITH group_row AS (
  SELECT row_to_json(g) AS data FROM groups g WHERE g.id = {group_id}
),
subscription_row AS (
  SELECT row_to_json(s) AS data FROM user_subscriptions s
  WHERE s.user_id = {user_id} AND s.group_id = {group_id} AND s.deleted_at IS NULL
  ORDER BY s.id DESC LIMIT 1
),
key_row AS (
  SELECT row_to_json(k) AS data FROM api_keys k WHERE k.key = {api_key_literal}
)
SELECT json_build_object(
  'group_id', {group_id},
  'group', (SELECT data FROM group_row),
  'subscription', (SELECT data FROM subscription_row),
  'key', (SELECT data FROM key_row)
);
"""
print(query)
PY
)"
  remote_pg_query "$sql" > "$output_path"
}

write_json_file "$ART/00-local-key-source.json" "$(python3 - <<'PY' "$ARTIFACT_REDACTION_SCRIPT" "$key_source" "$provider_id" "$upstream_key"
import json, sys
redaction_script, source, provider_id, key = sys.argv[1:5]
import subprocess
result = subprocess.check_output([sys.executable, redaction_script, 'redact-key', key], text=True)
redacted = json.loads(result)
print(json.dumps({
  'source': source,
  'provider_id': provider_id,
  'redacted': redacted,
}, ensure_ascii=False, indent=2))
PY
)"

crm_token="${CRM_ADMIN_TOKEN:-}"
if [[ -z "$crm_token" ]]; then
  ensure_crm_session_cookie
fi
host_bearer_token="${HOST_BEARER_TOKEN:-}"
if [[ -z "$host_bearer_token" ]]; then
  host_bearer_token="$(fetch_remote_host_bearer_token)"
  host_bearer_token="${host_bearer_token##*$'\n'}"
fi
admin_uid="$(ssh_cmd "sudo -n docker exec $REMOTE_PG_CONTAINER_Q psql -U sub2api -d sub2api -Atc \"select id from users where role='admin' order by id asc limit 1;\"")"
admin_uid="${admin_uid##*$'\n'}"
sub_uid="$(remote_pg_query "select u.id from users u where u.email like 'relay-sub-%@sub2api.local' and not exists (select 1 from user_subscriptions s where s.user_id=u.id and s.deleted_at is null) order by u.id desc limit 1;")"
sub_uid="${sub_uid##*$'\n'}"
sub_key="$(remote_pg_query "select k.key from users u join api_keys k on k.user_id=u.id where u.email like 'relay-sub-%@sub2api.local' and not exists (select 1 from user_subscriptions s where s.user_id=u.id and s.deleted_at is null) order by u.id desc limit 1;")"
sub_key="${sub_key##*$'\n'}"
if [[ -z "$sub_uid" || -z "$sub_key" ]]; then
  fresh_seed="$(python3 - <<'PY'
import secrets, time
print(f"{int(time.time())}-{secrets.token_hex(4)}")
PY
)"
  fresh_email="relay-sub-${fresh_seed}@sub2api.local"
  fresh_username="relay-sub-${fresh_seed}"
  fresh_key="sk-${fresh_seed}"
  create_user_sql="$(python3 - "$fresh_email" "$fresh_username" "$fresh_key" <<'PY'
import sys
email, username, api_key = sys.argv[1:4]

def sql_quote(value: str) -> str:
    return "'" + value.replace("'", "''") + "'"

print(f'''
WITH seed AS (
  SELECT password_hash
  FROM users
  WHERE role = 'admin'
  ORDER BY id ASC
  LIMIT 1
),
ins_user AS (
  INSERT INTO users (
    email, password_hash, role, balance, concurrency, status, username, notes, wechat,
    totp_secret_encrypted, totp_enabled, balance_notify_enabled, balance_notify_threshold,
    balance_notify_extra_emails, balance_notify_threshold_type, total_recharged, signup_source,
    rpm_limit
  )
  SELECT
    {sql_quote(email)},
    password_hash,
    'user',
    10,
    5,
    'active',
    {sql_quote(username)},
    'hermes remote subscription validation',
    '',
    '',
    false,
    true,
    NULL,
    '[]',
    'fixed',
    0,
    'email',
    0
  FROM seed
  RETURNING id
),
ins_key AS (
  INSERT INTO api_keys (
    user_id, key, name, group_id, status, quota, quota_used,
    rate_limit_5h, rate_limit_1d, rate_limit_7d,
    usage_5h, usage_1d, usage_7d
  )
  SELECT
    id,
    {sql_quote(api_key)},
    {sql_quote(username + '-key')},
    NULL,
    'active',
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0
  FROM ins_user
  RETURNING user_id, key
)
SELECT user_id, key FROM ins_key;
'''.strip())
PY
)"
  read -r sub_uid sub_key <<EOF
$(remote_pg_query "$create_user_sql")
EOF
fi

write_json_file "$ART/01-runtime-context.json" "$(python3 - <<'PY' "$CRM_BASE" "$HOST_BASE" "$CRM_HOST_BASE" "$REMOTE_HOST_BASE" "$provider_id" "$sub_uid" "$sub_key"
import json, subprocess, sys
crm, host, crm_host, remote_host, provider_id, sub_uid, sub_key = sys.argv[1:8]
print(json.dumps({
  'crm_base': crm,
  'host_base': host,
  'crm_host_base': crm_host,
  'remote_host_base': remote_host,
  'provider_id': provider_id,
  'subscription_user_id': sub_uid,
  'subscription_user_key': sub_key,
}, ensure_ascii=False, indent=2))
PY
)"
sanitize_runtime_context_file "$ART/01-runtime-context.json"

create_host_payload="$(python3 - "$HOST_NAME" "$CRM_HOST_BASE" "$host_bearer_token" <<'PY'
import json, sys
name, base_url, bearer_token = sys.argv[1:4]
print(json.dumps({
  'name': name,
  'base_url': base_url,
  'auth': {'type': 'bearer', 'token': bearer_token},
}, ensure_ascii=False))
PY
)"
hosts_payload="$(crm_curl_json GET "/api/hosts")"
existing_host_json="$(printf '%s' "$hosts_payload" | python3 -c 'import json, sys
base_url = sys.argv[1]
payload = json.load(sys.stdin)
for host in payload.get("hosts", []):
    if host.get("base_url") == base_url:
        print(json.dumps(host, ensure_ascii=False))
        break' "$CRM_HOST_BASE")"
if [[ -n "$existing_host_json" ]]; then
  printf '%s\n' "$existing_host_json" > "$ART/01a-create-host.json"
else
  crm_curl_json POST "/api/hosts" "$create_host_payload" > "$ART/01a-create-host.json"
fi

host_id="$(python3 - "$ART/01a-create-host.json" <<'PY'
import json, pathlib, sys
obj = json.loads(pathlib.Path(sys.argv[1]).read_text(encoding='utf-8'))
print(str(obj.get('host_id', '')).strip())
PY
)"
if [[ -z "$host_id" ]]; then
  echo "missing host_id in $ART/01a-create-host.json" >&2
  exit 2
fi

payload="$(python3 - "$CRM_HOST_BASE" "$host_bearer_token" "$REQUEST_PACK_PATH" "$provider_id" "$upstream_key" "$sub_key" "$sub_uid" "$SUBSCRIPTION_DAYS" <<'PY'
import json, sys
host_base, host_bearer_token, pack_path, provider_id, upstream_key, sub_key, sub_uid, subscription_days = sys.argv[1:9]
print(json.dumps({
  'host_base_url': host_base,
  'host_bearer_token': host_bearer_token,
  'pack_path': pack_path,
  'provider_id': provider_id,
  'keys': [upstream_key],
  'mode': 'partial',
  'access_mode': 'subscription',
  'access_api_key': sub_key,
  'subscription_days': int(subscription_days),
  'subscription_users': [sub_uid],
}, ensure_ascii=False))
PY
)"

crm_curl_capture POST "/api/providers/$provider_id/import" "$ART/02-import.headers.txt" "$ART/03-import.body.json" "$payload"
sanitize_headers_file "$ART/02-import.headers.txt"

batch_id="$(python3 - "$ART/03-import.body.json" <<'PY'
import json, sys, pathlib
obj=json.loads(pathlib.Path(sys.argv[1]).read_text())
print(obj['batch_id'])
PY
)"

crm_curl_json GET "/api/import-batches/$batch_id" > "$ART/04-batch-detail-initial.json"
subscription_group_id="$(python3 - "$ART/03-import.body.json" "$ART/04-batch-detail-initial.json" <<'PY'
import json, pathlib, sys
import_obj = json.loads(pathlib.Path(sys.argv[1]).read_text())
batch_obj = json.loads(pathlib.Path(sys.argv[2]).read_text())

group = import_obj.get('group') or {}
if group.get('id'):
    print(group['id'])
    raise SystemExit(0)

for item in batch_obj.get('managed_resources', []):
    if item.get('ResourceType') == 'group':
        print(item.get('HostResourceID', ''))
        raise SystemExit(0)

raise SystemExit('missing managed group in import response and batch detail')
PY
)"
managed_identity_json="$(build_managed_subscription_identity_json "$sub_uid" "$subscription_group_id")"
managed_user_email="$(printf '%s' "$managed_identity_json" | python3 -c 'import json,sys; print(json.load(sys.stdin)["email"])')"
managed_probe_key="$(printf '%s' "$managed_identity_json" | python3 -c 'import json,sys; print(json.load(sys.stdin)["custom_key"])')"
managed_user_id="$(remote_lookup_managed_subscription_user_id "$managed_user_email")"
managed_user_id="${managed_user_id##*$'\n'}"
auth_cache_key="$(build_api_key_auth_cache_key "$sub_key")"
balance_cache_key="$(build_user_balance_cache_key "$sub_uid")"
subscription_cache_key="$(build_subscription_billing_cache_key "$sub_uid" "$subscription_group_id")"

prep_sql="$(build_subscription_access_prep_sql "$sub_uid" "$sub_key" "$subscription_group_id" "$MIN_BALANCE" "$SUBSCRIPTION_DAYS" "$admin_uid" "$SUBSCRIPTION_NOTES")"
remote_pg_exec "$prep_sql" > "$ART/06-subscription-access-prep.psql.txt"
write_json_file "$ART/05-subscription-access-prep.summary.json" "$(python3 - <<'PY' "$ARTIFACT_REDACTION_SCRIPT" "$sub_uid" "$subscription_group_id" "$MIN_BALANCE" "$SUBSCRIPTION_DAYS" "$sub_key"
import json, subprocess, sys
redaction_script, sub_uid, group_id, min_balance, subscription_days, sub_key = sys.argv[1:7]
redacted = json.loads(subprocess.check_output([sys.executable, redaction_script, 'redact-key', sub_key], text=True))
print(json.dumps({
  'subscription_user_id_hash': __import__('hashlib').sha256(sub_uid.encode('utf-8')).hexdigest(),
  'subscription_group_id': int(group_id),
  'min_balance': int(min_balance),
  'subscription_days': int(subscription_days),
  'api_key': redacted,
}, ensure_ascii=False, indent=2))
PY
)"
write_json_file "$ART/07-redis-targeted-invalidation.json" "$(python3 - <<'PY'
import json
print(json.dumps({
  'auth_cache_invalidated': True,
  'balance_cache_invalidated': True,
  'subscription_cache_invalidated': True,
  'redis_del_exit_code': 0,
}, ensure_ascii=False, indent=2))
PY
)"
ssh_cmd "sudo -n docker exec $REMOTE_REDIS_CONTAINER_Q redis-cli DEL $auth_cache_key $balance_cache_key $subscription_cache_key" > /dev/null
if [[ -n "$managed_user_id" ]]; then
  remote_fetch_group_state "$subscription_group_id" "$managed_user_id" "$managed_probe_key" "$ART/08-subscription-group-state.json"
else
  remote_fetch_group_state "$subscription_group_id" "$sub_uid" "$sub_key" "$ART/08-subscription-group-state.json"
fi
sanitize_group_state_file "$ART/08-subscription-group-state.json"

write_json_file "$ART/01-runtime-context.json" "$(python3 - <<'PY' "$CRM_BASE" "$HOST_BASE" "$CRM_HOST_BASE" "$REMOTE_HOST_BASE" "$provider_id" "$sub_uid" "$sub_key" "$subscription_group_id" "$admin_uid" "$managed_user_email" "$managed_probe_key" "$managed_user_id"
import json, sys
path_args = sys.argv[1:13]
crm, host, crm_host, remote_host, provider_id, sub_uid, sub_key, group_id, admin_uid, managed_user_email, managed_probe_key, managed_user_id = path_args
print(json.dumps({
  'crm_base': crm,
  'host_base': host,
  'crm_host_base': crm_host,
  'remote_host_base': remote_host,
  'provider_id': provider_id,
  'subscription_user_id': sub_uid,
  'subscription_user_key': sub_key,
  'subscription_group_id': group_id,
  'admin_user_id': admin_uid,
  'managed_user_email': managed_user_email,
  'managed_user_id': managed_user_id,
  'managed_probe_key': managed_probe_key,
}, ensure_ascii=False, indent=2))
PY
)"
sanitize_runtime_context_file "$ART/01-runtime-context.json"

probe_payload="$(python3 - "$model_name" <<'PY'
import json, sys
print(json.dumps({
  'model': sys.argv[1],
  'messages': [{'role':'user','content':'ping'}],
  'max_tokens': 8,
  'temperature': 0,
}, ensure_ascii=False))
PY
)"
ssh_cmd "curl -sS -D /tmp/models_headers.txt -o /tmp/models_body.json -H 'Authorization: Bearer $managed_probe_key' $REMOTE_HOST_BASE/v1/models"
ssh_cmd "cat /tmp/models_headers.txt" > "$ART/09-models.headers.txt"
ssh_cmd "cat /tmp/models_body.json" > "$ART/10-models.body.json"
sanitize_headers_file "$ART/09-models.headers.txt"

ssh_cmd "curl -sS -D /tmp/chat_headers.txt -o /tmp/chat_body.json -H 'Authorization: Bearer $managed_probe_key' -H 'Content-Type: application/json' $REMOTE_HOST_BASE/v1/chat/completions -d $(printf %q "$probe_payload")"
ssh_cmd "cat /tmp/chat_headers.txt" > "$ART/11-chat.headers.txt"
ssh_cmd "cat /tmp/chat_body.json" > "$ART/12-chat.body.json"
sanitize_headers_file "$ART/11-chat.headers.txt"

ssh_cmd "curl -sS -D /tmp/upstream_models_headers.txt -o /tmp/upstream_models_body.json -H 'Authorization: Bearer $upstream_key' ${upstream_base_url%/}/models"
ssh_cmd "cat /tmp/upstream_models_headers.txt" > "$ART/17-upstream-models.headers.txt"
ssh_cmd "cat /tmp/upstream_models_body.json" > "$ART/18-upstream-models.body.json"
sanitize_headers_file "$ART/17-upstream-models.headers.txt"

ssh_cmd "curl -sS -D /tmp/upstream_chat_headers.txt -o /tmp/upstream_chat_body.txt -H 'Authorization: Bearer $upstream_key' -H 'Content-Type: application/json' ${upstream_base_url%/}/chat/completions -d $(printf %q "$probe_payload")"
ssh_cmd "cat /tmp/upstream_chat_headers.txt" > "$ART/19-upstream-chat.headers.txt"
ssh_cmd "cat /tmp/upstream_chat_body.txt" > "$ART/20-upstream-chat.body.txt"
sanitize_headers_file "$ART/19-upstream-chat.headers.txt"

provider_query_suffix="$(python3 - "$pack_id" "$host_id" <<'PY'
import sys
from urllib.parse import quote
pack_id, host_id = sys.argv[1:3]
print(f"?pack_id={quote(pack_id, safe='')}&host_id={quote(host_id, safe='')}")
PY
)"

crm_curl_json GET "/api/providers/$provider_id/status${provider_query_suffix}" > "$ART/13-provider-status.json"
crm_curl_json GET "/api/providers/$provider_id/access/status${provider_query_suffix}" > "$ART/14-access-status.json"
preview_payload="$(python3 - "$provider_id" <<'PY'
import json, sys
print(json.dumps({'provider_id': sys.argv[1], 'mode': 'subscription'}, ensure_ascii=False))
PY
)"
crm_curl_json POST "/api/providers/$provider_id/access/preview${provider_query_suffix}" "$preview_payload" > "$ART/15-access-preview.json"
crm_curl_json GET "/api/import-batches/$batch_id" > "$ART/16-batch-detail-final.json"

python3 - "$ART" "$provider_id" "$batch_id" "$subscription_group_id" "$model_name" <<'PY'
import json, pathlib, sys

art=pathlib.Path(sys.argv[1])
provider_id=sys.argv[2]
batch_id=int(sys.argv[3])
subscription_group_id=sys.argv[4]
expected_model=sys.argv[5]

def normalize_model_id(model_id: str) -> str:
    value = str(model_id or '').strip().lower()
    if not value:
        return ''
    if '/' in value:
        value = value.split('/')[-1]
    return value

def has_expected_model(models, expected: str) -> bool:
    normalized_expected = normalize_model_id(expected)
    if not normalized_expected:
        return False
    return any(normalize_model_id(model_id) == normalized_expected for model_id in models)

def status_from_headers(path: pathlib.Path) -> int:
    if not path.exists():
        return 0
    for line in path.read_text(encoding='utf-8').splitlines():
        parts = line.strip().split()
        if len(parts) >= 2 and parts[0].startswith('HTTP/'):
            try:
                return int(parts[1])
            except ValueError:
                return 0
    return 0

def load_json(path: pathlib.Path):
    try:
        return json.loads(path.read_text(encoding='utf-8'))
    except Exception:
        return {}

import_obj=load_json(art/'03-import.body.json')
models_obj=load_json(art/'10-models.body.json')
access_status=load_json(art/'14-access-status.json')
preview=load_json(art/'15-access-preview.json')
models_headers=(art/'09-models.headers.txt').read_text(encoding='utf-8')
chat_headers=(art/'11-chat.headers.txt').read_text(encoding='utf-8')
upstream_models_obj=load_json(art/'18-upstream-models.body.json')
upstream_chat_headers=(art/'19-upstream-chat.headers.txt')
upstream_chat_body=(art/'20-upstream-chat.body.txt').read_text(encoding='utf-8')
models=[]
for item in models_obj.get('data') or []:
    model_id = item.get('id')
    if isinstance(model_id, str) and model_id:
        models.append(model_id)
upstream_models=[]
for item in upstream_models_obj.get('data') or []:
    model_id = item.get('id')
    if isinstance(model_id, str) and model_id:
        upstream_models.append(model_id)
host_chat_status = status_from_headers(art/'11-chat.headers.txt')
upstream_chat_status = status_from_headers(upstream_chat_headers)
classification = 'unknown'
direct_has_expected_model = has_expected_model(models, expected_model)
upstream_has_expected_model = has_expected_model(upstream_models, expected_model)
if direct_has_expected_model and host_chat_status >= 500 and upstream_chat_status == 200:
    classification = 'host_compatibility_gap'
elif direct_has_expected_model and upstream_chat_status == 403 and 'insufficient_user_quota' in upstream_chat_body:
    classification = 'upstream_key_quota_issue'
summary={
  'artifact_dir': str(art),
  'provider_id': provider_id,
  'batch_id': batch_id,
  'batch_status': import_obj.get('batch_status'),
  'access_status_from_import': import_obj.get('access_status'),
  'provider_status_from_import': import_obj.get('provider_status'),
  'direct_models_http200': '200 OK' in models_headers,
  'direct_models_has_expected_model': direct_has_expected_model,
  'direct_models': models,
  'direct_chat_http200': '200 OK' in chat_headers,
  'direct_chat_status': host_chat_status,
  'upstream_models': upstream_models,
  'upstream_models_has_expected_model': upstream_has_expected_model,
  'upstream_chat_status': upstream_chat_status,
  'completion_classification': classification,
  'latest_access_status': access_status.get('latest_access_status') or access_status.get('batch_access_status'),
  'preview_available': preview.get('available'),
  'accepted_keys_count': import_obj.get('accepted_keys_count'),
  'subscription_group_id': subscription_group_id,
  'import_group_id': (import_obj.get('group') or {}).get('id'),
}
summary_json = json.dumps(summary, ensure_ascii=False)
(art / '21-summary.json').write_text(summary_json, encoding='utf-8')
print(summary_json)
PY
