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

repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"

root_config="$(
  docker compose --env-file "$repo_root/.env" -f "$repo_root/compose.ory.yaml" config
)"
docker_config="$(
  docker compose --env-file "$repo_root/.env" -f "$repo_root/docker/compose.ory.yaml" config
)"

override_env="$(mktemp)"
cp "$repo_root/.env" "$override_env"
cat >> "$override_env" <<'EOF'
USERFRONT_URL=https://compose-policy.example.test/sso
HYDRA_PUBLIC_URL=https://compose-policy.example.test/sso/oidc
KRATOS_UI_URL=https://compose-policy.example.test/ui
KRATOS_BROWSER_URL=https://compose-policy.example.test/auth
ADMINFRONT_CALLBACK_URLS=https://compose-policy.example.test/admin/callback
DEVFRONT_CALLBACK_URLS=https://compose-policy.example.test/dev/callback
ORGFRONT_CALLBACK_URLS=https://compose-policy.example.test/org/callback
EOF
trap 'rm -f "$override_env"' EXIT

override_config="$(
  docker compose --env-file "$override_env" -f "$repo_root/compose.ory.yaml" config
)"
override_docker_config="$(
  docker compose --env-file "$override_env" -f "$repo_root/docker/compose.ory.yaml" config
)"

for service in kratos hydra keto oathkeeper; do
  version_key="$(tr '[:lower:]' '[:upper:]' <<<"$service")_VERSION"
  expected_version="$(grep -E "^${version_key}=" "$repo_root/.env" | cut -d= -f2-)"
  if [[ -z "$expected_version" ]]; then
    echo "ERROR: $version_key must be set in .env" >&2
    exit 1
  fi
  if ! grep -q "image: oryd/${service}:${expected_version}" <<<"$root_config"; then
    echo "ERROR: compose.ory.yaml must render oryd/${service}:${expected_version}" >&2
    exit 1
  fi
done

if grep -q "oryd/hydra:v25.4.0" <<<"$root_config"; then
  echo "ERROR: compose.ory.yaml must not hard-code init-rp to hydra v25.4.0." >&2
  exit 1
fi

for compose_file in "$repo_root/compose.ory.yaml" "$repo_root/docker/compose.ory.yaml"; do
  if grep -Eq 'redirect-uri .*:-.*https?://' "$compose_file"; then
    echo "ERROR: $compose_file must not hard-code external redirect URI fallbacks; use .env variables." >&2
    exit 1
  fi
  if grep -Eq 'KRATOS_SELFSERVICE_ALLOWED_RETURN_URLS=.*https?://localhost' "$compose_file"; then
    echo "ERROR: $compose_file must not hard-code Kratos allowed return URL fallbacks; use .env variables." >&2
    exit 1
  fi
  if awk 'in_block && /^    [A-Za-z0-9_-]+:/ { exit } /^    init-rp:/ { in_block=1 } in_block { print }' "$compose_file" | grep -q -- '--endpoint http://hydra:4445'; then
    echo "ERROR: $compose_file init-rp must use HYDRA_ADMIN_URL instead of hard-coded Hydra admin endpoint." >&2
    exit 1
  fi
  if awk 'in_block && /^    [A-Za-z0-9_-]+:/ { exit } /^[[:space:]]+oathkeeper:/ { in_block=1 } in_block { print }' "$compose_file" | grep -q "command: serve proxy --config /etc/config/oathkeeper/oathkeeper.yml"; then
    echo "ERROR: $compose_file Oathkeeper must use entrypoint.sh instead of bypassing rules.active.json generation." >&2
    exit 1
  fi
done

for stack_check_file in \
  "$repo_root/compose.ory.yaml" \
  "$repo_root/docker/compose.ory.yaml" \
  "$repo_root/docker/staging_pull_compose.template.yaml" \
  "$repo_root/deploy/templates/docker-compose.yaml"
do
  if grep -q 'until curl -s http://' "$stack_check_file"; then
    echo "ERROR: Ory stack check must not wait forever; use bounded readiness checks in $stack_check_file." >&2
    exit 1
  fi
  if ! grep -q 'ORY_STACK_CHECK_MAX_ATTEMPTS' "$stack_check_file"; then
    echo "ERROR: Ory stack check must expose ORY_STACK_CHECK_MAX_ATTEMPTS in $stack_check_file." >&2
    exit 1
  fi
  if ! grep -q 'ERROR: Ory service not ready' "$stack_check_file"; then
    echo "ERROR: Ory stack check must report the failed service name in $stack_check_file." >&2
    exit 1
  fi
  if ! grep -q 'check_ready kratos .* || exit 1' "$stack_check_file"; then
    echo "ERROR: Ory stack check must raise a non-zero exit when Kratos is not ready in $stack_check_file." >&2
    exit 1
  fi
done

for expected_url in \
  "https://compose-policy.example.test/sso/oidc" \
  "https://compose-policy.example.test/sso/login" \
  "https://compose-policy.example.test/sso/consent" \
  "https://compose-policy.example.test/sso/error" \
  "https://compose-policy.example.test/admin/callback" \
  "https://compose-policy.example.test/dev/callback" \
  "https://compose-policy.example.test/org/callback"
do
  if ! grep -q "$expected_url" <<<"$override_config$override_docker_config"; then
    echo "ERROR: Ory compose config must render env override URL: $expected_url" >&2
    exit 1
  fi
done

root_init_rp="$(
  awk 'in_block && /^    [A-Za-z0-9_-]+:/ { exit } /^    init-rp:/ { in_block=1 } in_block { print }' "$repo_root/compose.ory.yaml"
)"
docker_init_rp="$(
  awk 'in_block && /^    [A-Za-z0-9_-]+:/ { exit } /^    init-rp:/ { in_block=1 } in_block { print }' "$repo_root/docker/compose.ory.yaml"
)"
if grep -q "image: oryd/hydra" <<<"$root_init_rp$docker_init_rp"; then
  echo "ERROR: init-rp must not use the Hydra service image because distroless tags do not provide /bin/sh." >&2
  exit 1
fi

if ! grep -q "migrate sql up" "$repo_root/compose.ory.yaml"; then
  echo "ERROR: compose.ory.yaml Kratos migration must use migrate sql up." >&2
  exit 1
fi

if ! grep -q "keto-migrate:" <<<"$docker_config"; then
  echo "ERROR: docker/compose.ory.yaml must include keto-migrate for clean Ory installs." >&2
  exit 1
fi

if grep -q "releases/download/v25.4.0" "$repo_root/docker/staging_pull_compose.template.yaml"; then
  echo "ERROR: staging pull compose must not download a hard-coded Hydra v25.4.0 CLI." >&2
  exit 1
fi

staging_pull_template="$repo_root/docker/staging_pull_compose.template.yaml"

if ! grep -q 'entrypoint: \["/etc/config/oathkeeper/entrypoint.sh"\]' "$staging_pull_template"; then
  echo "ERROR: staging pull Oathkeeper must use the env-aware entrypoint." >&2
  exit 1
fi

if grep -q "command: serve proxy --config /etc/config/oathkeeper/oathkeeper.yml" "$staging_pull_template"; then
  echo "ERROR: staging pull Oathkeeper must not bypass entrypoint.sh with a direct command." >&2
  exit 1
fi

if ! grep -q "URLS_SELF_ISSUER=\${HYDRA_PUBLIC_URL}" "$staging_pull_template"; then
  echo "ERROR: staging pull Hydra issuer must use HYDRA_PUBLIC_URL." >&2
  exit 1
fi

if grep -Eq '(KRATOS_(SERVE|SELFSERVICE|UI|BROWSER|PUBLIC|ADMIN).*:-http://localhost|URLS_.*:-http://localhost)' "$staging_pull_template"; then
  echo "ERROR: staging pull Ory browser URLs must not fall back to localhost." >&2
  exit 1
fi

if ! grep -q 'KRATOS_SELFSERVICE_ALLOWED_RETURN_URLS=${KRATOS_ALLOWED_RETURN_URLS_JSON' "$staging_pull_template"; then
  echo "ERROR: staging pull Kratos allowed_return_urls must be driven by KRATOS_ALLOWED_RETURN_URLS_JSON." >&2
  exit 1
fi

for return_path in '/ko' '/en' '/auth/callback' '/ko/auth/callback' '/en/auth/callback'; do
  if ! grep -q "$return_path" "$staging_pull_template" "$repo_root/deploy/templates/.env.template" "$repo_root/.gitea/workflows/staging_code_pull.yml"; then
    echo "ERROR: staging/prod allowed_return_urls must include locale/callback path: $return_path" >&2
    exit 1
  fi
done

if grep -Eq 'ORGFRONT_CALLBACK_URLS=.*(172\.16\.10\.176|baron-orgchart\.hmac\.kr|, https?://)' "$staging_pull_template" "$repo_root/.gitea/workflows/staging_code_pull.yml"; then
  echo "ERROR: staging pull OrgFront callbacks must not keep private IP, legacy orgchart domain, or comma-space URI entries." >&2
  exit 1
fi

if grep -q "rewrite \\^/oidc" "$repo_root/gateway/nginx.conf"; then
  echo "ERROR: gateway must preserve the /oidc prefix and let Oathkeeper strip it." >&2
  exit 1
fi

for rules_file in \
  "$repo_root/docker/ory/oathkeeper/rules.json" \
  "$repo_root/docker/ory/oathkeeper/rules.stage.json" \
  "$repo_root/docker/ory/oathkeeper/rules.prod.json"
do
  for rule_id in hydra-well-known hydra-well-known-oidc hydra-oauth2 hydra-oauth2-oidc hydra-userinfo hydra-userinfo-oidc; do
    if ! grep -q "\"id\": \"$rule_id\"" "$rules_file"; then
      echo "ERROR: Oathkeeper rules must expose Hydra public route in $rules_file: $rule_id" >&2
      exit 1
    fi
  done
  for prefixed_rule in hydra-well-known-oidc hydra-oauth2-oidc hydra-userinfo-oidc; do
    if ! awk -v id="\"id\": \"$prefixed_rule\"" '
      $0 ~ id { in_rule = 1 }
      in_rule && /strip_path/ && /\/oidc/ { found = 1 }
      in_rule && /^  }[,]?$/ { in_rule = 0 }
      END { exit found ? 0 : 1 }
    ' "$rules_file"; then
      echo "ERROR: prefixed Oathkeeper route must strip /oidc in $rules_file: $prefixed_rule" >&2
      exit 1
    fi
  done
done

for wildcard_rules_file in \
  "$repo_root/docker/ory/oathkeeper/rules.json" \
  "$repo_root/docker/ory/oathkeeper/rules.stage.json"
do
  if grep -q "<\\.\\*>://<\\.\\*>/" "$wildcard_rules_file"; then
    echo "ERROR: wildcard Oathkeeper host must not swallow path segments in $wildcard_rules_file." >&2
    exit 1
  fi
done

deploy_template="$repo_root/deploy/templates/docker-compose.yaml"
deploy_env_template="$repo_root/deploy/templates/.env.template"
deploy_gateway_template="$repo_root/deploy/templates/gateway/nginx.conf"
deploy_kratos_template="$repo_root/deploy/templates/ory/kratos/kratos.yml.template"
deploy_oathkeeper_rules_template="$repo_root/deploy/templates/ory/oathkeeper/rules.json"

for required_template in \
  "$repo_root/deploy/templates/orgfront/vite.config.ts" \
  "$repo_root/deploy/templates/orgfront/auth.ts" \
  "$repo_root/docker/ory/init-db/01_create_dbs.sh" \
  "$repo_root/docker/ory/hydra/hydra.yml.template" \
  "$repo_root/docker/ory/keto/keto.yml.template" \
  "$repo_root/docker/ory/oathkeeper/entrypoint.sh" \
  "$repo_root/docker/ory/oathkeeper/oathkeeper.yml.template"
do
  if [[ ! -f "$required_template" ]]; then
    echo "ERROR: deploy instance generation requires missing source file: $required_template" >&2
    exit 1
  fi
done

if grep -Eq "oryd/(kratos|hydra|keto|oathkeeper):v25\\.4\\.0" "$deploy_template"; then
  echo "ERROR: deploy template Ory stack must not hard-code v25.4.0 images." >&2
  exit 1
fi

for prod_sensitive_file in \
  "$repo_root/docker/ory/oathkeeper/rules.prod.json" \
  "$repo_root/docker/ory/kratos/kratos.yml.template" \
  "$repo_root/deploy/templates/ory/kratos/kratos.yml.template"
do
  if grep -q "app\\.brsw\\.kr" "$prod_sensitive_file"; then
    echo "ERROR: Ory production-sensitive config must not hard-code app.brsw.kr: $prod_sensitive_file" >&2
    exit 1
  fi
done

for compose_file in "$repo_root/compose.ory.yaml" "$repo_root/docker/compose.ory.yaml" "$repo_root/docker/staging_pull_compose.template.yaml"; do
  if grep -Eq './docker/ory/(kratos|hydra|keto|oathkeeper):/etc/config/' "$compose_file"; then
    echo "ERROR: Ory compose must mount rendered config/.generated/ory config, not source templates: $compose_file" >&2
    exit 1
  fi
done

if grep -Eq '\./ory/(kratos|hydra|keto|oathkeeper):/etc/config/' "$deploy_template"; then
  echo "ERROR: deploy template must mount rendered config/.generated/ory config, not source templates." >&2
  exit 1
fi

if grep -q 'ory/generated' "$deploy_template" "$repo_root/deploy/create-instance.sh"; then
  echo "ERROR: deploy template must use config/.generated/ory, not ory/generated." >&2
  exit 1
fi

if ! grep -q '^render-ory-config:' "$repo_root/Makefile"; then
  echo "ERROR: Makefile must render Ory config before starting Ory services." >&2
  exit 1
fi
if ! awk '/^ensure-ory:/ { in_target=1 } in_target && /^[^[:space:]].*:/ && $0 !~ /^ensure-ory:/ { exit } in_target { print }' "$repo_root/Makefile" | grep -q 'restart kratos'; then
  echo "ERROR: make up-dev must restart Kratos when Ory is already running so rendered dev config is applied." >&2
  exit 1
fi
if ! awk '/^up-all:/ { in_target=1 } in_target && /^[^[:space:]].*:/ && $0 !~ /^up-all:/ { exit } in_target { print }' "$repo_root/Makefile" | grep -q 'restart kratos'; then
  echo "ERROR: make up must restart Kratos after rendering Ory config." >&2
  exit 1
fi
if ! awk '/^up-ory:/ { in_target=1 } in_target && /^[^[:space:]].*:/ && $0 !~ /^up-ory:/ { exit } in_target { print }' "$repo_root/Makefile" | grep -q 'restart kratos'; then
  echo "ERROR: make up-ory must restart Kratos after rendering Ory config." >&2
  exit 1
fi

if ! grep -q 'scripts/render_ory_config.sh' "$repo_root/.gitea/workflows/staging_code_pull.yml"; then
  echo "ERROR: staging code pull must render Ory config before docker compose up." >&2
  exit 1
fi

if ! grep -q 'up -d --force-recreate kratos hydra keto oathkeeper' "$repo_root/.gitea/workflows/staging_code_pull.yml"; then
  echo "ERROR: staging code pull must restart Ory services after rendering static config." >&2
  exit 1
fi

if grep -Eq '^[[:space:]]*rm -rf "?\$OUTPUT_DIR"?[[:space:]]*$' "$repo_root/scripts/render_ory_config.sh"; then
  echo "ERROR: Ory renderer must preserve config/.generated/ory service directories so live bind mounts stay valid." >&2
  exit 1
fi

"$repo_root/scripts/render_ory_config.sh" >/dev/null
local_rendered_kratos="$repo_root/config/.generated/ory/kratos/kratos.yml"
if ! awk '/session:/ { in_session=1 } in_session && /domain:/ { print; exit }' "$local_rendered_kratos" | grep -q 'domain: localhost'; then
  echo "ERROR: rendered local Kratos config must use localhost as session.cookie.domain for dev runs." >&2
  exit 1
fi

stage_render_dir="$(mktemp -d)"
stage_render_env="$(mktemp)"
cat > "$stage_render_env" <<'EOF'
USERFRONT_URL=https://sso.hmac.kr
ADMINFRONT_URL=https://sadmin.hmac.kr
DEVFRONT_URL=https://sdev.hmac.kr
ORGFRONT_URL=https://sorg.hmac.kr
KRATOS_UI_URL=https://sso.hmac.kr
KRATOS_BROWSER_URL=https://sso.hmac.kr/auth
KRATOS_ADMIN_URL=http://kratos:4434
ORY_POSTGRES_PASSWORD=policy-test
KRATOS_ALLOWED_RETURN_URLS_JSON=
KRATOS_ALLOWED_RETURN_URLS_EXTRA=
EOF
ORY_CONFIG_ENV_FILES="$stage_render_env" ORY_CONFIG_OUTPUT_DIR="$stage_render_dir/ory" "$repo_root/scripts/render_ory_config.sh" >/dev/null
stage_rendered_kratos="$stage_render_dir/ory/kratos/kratos.yml"
if ! awk '/allowed_return_urls:/ { in_block=1; next } in_block && /^[[:space:]]+methods:/ { exit } in_block { print }' "$stage_rendered_kratos" | grep -q 'https://sso.hmac.kr'; then
  echo "ERROR: rendered stage Kratos config must include the public userfront URL in allowed_return_urls." >&2
  exit 1
fi
if awk '/allowed_return_urls:/ { in_block=1; next } in_block && /^[[:space:]]+methods:/ { exit } in_block { print }' "$stage_rendered_kratos" | grep -q 'http://localhost:5000'; then
  echo "ERROR: rendered stage Kratos allowed_return_urls must not fall back to localhost." >&2
  exit 1
fi
if ! awk '/session:/ { in_session=1 } in_session && /domain:/ { print; exit }' "$stage_rendered_kratos" | grep -q 'domain: hmac.kr'; then
  echo "ERROR: rendered stage Kratos config must derive hmac.kr as session.cookie.domain." >&2
  exit 1
fi
rm -rf "$stage_render_dir" "$stage_render_env"

for generated_config in \
  "$repo_root/config/.generated/ory/kratos/kratos.yml" \
  "$repo_root/config/.generated/ory/hydra/hydra.yml" \
  "$repo_root/config/.generated/ory/keto/keto.yml" \
  "$repo_root/config/.generated/ory/oathkeeper/oathkeeper.yml"
do
  if [[ ! -f "$generated_config" ]]; then
    echo "ERROR: Ory rendered config is missing: $generated_config" >&2
    exit 1
  fi
  if grep -q '\${' "$generated_config"; then
    echo "ERROR: Ory rendered config must not contain placeholders: $generated_config" >&2
    exit 1
  fi
done

for service in kratos-migrate kratos hydra-migrate hydra keto-migrate keto oathkeeper_logs_init oathkeeper; do
  if ! grep -q "^  $service:" "$deploy_template"; then
    echo "ERROR: deploy template Ory stack must include service: $service" >&2
    exit 1
  fi
done

for version_key in KRATOS_VERSION HYDRA_VERSION KETO_VERSION OATHKEEPER_VERSION; do
  if ! grep -q "^$version_key=v26\\.2\\.0$" "$deploy_env_template"; then
    echo "ERROR: deploy env template must define $version_key=v26.2.0." >&2
    exit 1
  fi
done

if ! grep -q 'entrypoint: \["/etc/config/oathkeeper/entrypoint.sh"\]' "$deploy_template"; then
  echo "ERROR: deploy template Oathkeeper must use the env-aware entrypoint." >&2
  exit 1
fi

if grep -q "rewrite \\^/oidc" "$deploy_gateway_template"; then
  echo "ERROR: deploy template gateway must preserve the /oidc prefix." >&2
  exit 1
fi

if ! grep -q '^version: v26.2.0$' "$deploy_kratos_template"; then
  echo "ERROR: deploy Kratos template config version must match v26.2.0." >&2
  exit 1
fi

for rule_id in hydra-well-known hydra-well-known-oidc hydra-oauth2 hydra-oauth2-oidc hydra-userinfo hydra-userinfo-oidc; do
  if ! grep -q "\"id\": \"$rule_id\"" "$deploy_oathkeeper_rules_template"; then
    echo "ERROR: deploy Oathkeeper rules must expose Hydra public route: $rule_id" >&2
    exit 1
  fi
done

if ! grep -q '"strip_path": "/oidc"' "$deploy_oathkeeper_rules_template"; then
  echo "ERROR: deploy Oathkeeper prefixed routes must strip /oidc with strip_path." >&2
  exit 1
fi
