#!/usr/bin/env bash
# scripts/run_codegen.sh — pre-Terraform codegen for the Nova platform pipeline.
#
# Performs steps 0–3b of run_platform.sh:
#   0. Environment onboarding check
#   1. Validate contract against contract.schema.json
#   2. Resolve contract → Target Stack instance (contract_resolver.py)
#   3. Adapter compiles stack → Terraform (adapter.py)
#   3b. Structural validation of emitted TF (offline)
#
# Emits Terraform files to $NOVA_WORK_DIR/tf/{main.tf,terraform.tf,providers.tf}
# and prints the work dir path for the caller (workflow or run_platform.sh)
# to use for native terraform init/validate/plan/apply steps.
#
# Usage:
#   run_codegen.sh <contract.yml> [--environment <name>] [--check-only]
#
# When --check-only is passed, exits 0 after structural validation (no AWS).
# Otherwise, loads AWS credentials from .env.secrets if not already set,
# and exits 0 with the work dir ready for terraform.
#
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
CALLER_CWD="$(pwd)"
cd "$ROOT"

CHECK_ONLY=0
ENVIRONMENT_OVERRIDE=""
CONTRACT=""

while [ $# -gt 0 ]; do
  case "$1" in
    --check-only) CHECK_ONLY=1; shift ;;
    --environment) shift; ENVIRONMENT_OVERRIDE="$1"; shift ;;
    --environment=*) ENVIRONMENT_OVERRIDE="${1#--environment=}"; shift ;;
    -h|--help)
      echo "Usage: run_codegen.sh <contract.yml> [--environment <name>] [--check-only]"
      exit 0 ;;
    *) CONTRACT="$1"; shift ;;
  esac
done

[ -n "$CONTRACT" ] || { echo "FAIL: no contract file specified" >&2; exit 1; }

# Resolve relative contract path against caller's CWD
if ! [[ "$CONTRACT" = /* ]]; then
  CONTRACT="$CALLER_CWD/$CONTRACT"
fi
[ -f "$CONTRACT" ] || { echo "FAIL: contract not found: $CONTRACT" >&2; exit 1; }

if [ -n "$ENVIRONMENT_OVERRIDE" ]; then
  export NOVA_ENVIRONMENT_OVERRIDE="$ENVIRONMENT_OVERRIDE"
fi

CONTRACT_ID="${NOVA_CONTRACT_ID:-11111111-1111-1111-1111-111111111111}"
WORK="${NOVA_WORK_DIR:-/tmp/nova_platform_run}"
TF_DIR="$WORK/tf"
rm -rf "$WORK"; mkdir -p "$TF_DIR"

echo "=== Step 0: environment onboarding check ==="
if [ -n "$ENVIRONMENT_OVERRIDE" ]; then
  python3 core/environment_check.py --env="$ENVIRONMENT_OVERRIDE" || {
    echo "FAIL: environment onboarding check failed for $ENVIRONMENT_OVERRIDE" >&2
    exit 1
  }
else
  python3 core/environment_check.py || true
fi

echo ""
echo "=== Step 1: validate contract against contract.schema.json ==="
python3 -c "
import json, sys, yaml
from jsonschema import validate
schema = json.load(open('schemas/contract.schema.json'))
doc = yaml.safe_load(open('$CONTRACT'))
validate(instance=doc, schema=schema)
print(f'contract valid: {doc.get(\"name\", \"unnamed\")} (env={doc.get(\"environment\",\"dev\")})')
"

echo ""
echo "=== Step 2: resolve contract → Target Stack instance ==="
python3 -c "
import json, sys
sys.path.insert(0, '$ROOT')
from core.contract_resolver import resolve
stack = resolve('$CONTRACT', environment_override='${ENVIRONMENT_OVERRIDE}' or None)
json.dump(stack, open('$WORK/stack.json', 'w'), indent=2)
print(f'stack resolved: {stack[\"stack\"][\"name\"]} ({len(stack[\"resources\"])} resource(s))')
"

echo ""
echo "=== Step 3: adapter compiles stack → $TF_DIR/*.tf ==="
python3 -c "
import json, sys
sys.path.insert(0, '$ROOT')
from adapters.terraform.adapter import TerraformAdapter
stack = json.load(open('$WORK/stack.json'))
adapter = TerraformAdapter()
adapter.compile(stack, '$TF_DIR')
print('adapter: main.tf + terraform.tf + providers.tf written')
"

echo "=== Step 3c: Checkov on static code (fail-fast, before terraform plan) ==="
# REQ-250 (v1.21): Checkov runs on the authored Terraform code BEFORE
# terraform plan so developers get immediate policy feedback, not a
# delayed plan-stage failure. The runtime plan scan (Wiz-or-Checkov)
# runs after the plan in run_postapply.sh Step 5.
if [ "$QUIET" = "0" ]; then
  checkov -d "$TF_DIR" --framework terraform -o json --soft-fail --external-checks-dir adapters/terraform/policy/custom_rules/ 2>&1 | tee "$WORK/checkov-static.json"
else
  checkov -d "$TF_DIR" --framework terraform -o json --soft-fail --external-checks-dir adapters/terraform/policy/custom_rules/ > "$WORK/checkov-static.json" 2> "$WORK/checkov-static.err"
fi
[ -s "$WORK/checkov-static.json" ] || { echo "FAIL: checkov (static) produced no output" >&2; exit 1; }
echo ""
echo "checkov (static) summary: $(python3 -c "import json; d=json.load(open('$WORK/checkov-static.json')); print(len(d.get('results',{}).get('failed_checks',[])), 'failed,', len(d.get('results',{}).get('passed_checks',[])), 'passed')")"

if [ "$CHECK_ONLY" = "1" ]; then
  echo ""
  echo "=== Step 3b: validate adapter output structure (offline) ==="
  python3 -c "
import json, os
d = json.load(open('$WORK/stack.json'))
assert d['stack']['name'], 'stack name missing'
assert len(d['resources']) >= 1, 'expected at least 1 resource'
tf_dir = '$TF_DIR'
for f in ('main.tf', 'terraform.tf', 'providers.tf'):
    assert os.path.isfile(os.path.join(tf_dir, f)), f'{f} missing'
main = open(os.path.join(tf_dir, 'main.tf')).read()
assert len(main) > 0, 'main.tf is empty'
tf = open(os.path.join(tf_dir, 'terraform.tf')).read()
assert 'backend' in tf
assert 'required_version' in tf
prov = open(os.path.join(tf_dir, 'providers.tf')).read()
assert 'provider \"aws\"' in prov
print(f\"adapter output: OK ({d['stack']['name']}, {len(d['resources'])} resource(s))\")
"
  echo ""
  echo "=== CODEGEN CHECK OK ==="
  echo "contract → resolver → stack → adapter → structure validated (offline, no AWS)"
  echo "WORK_DIR=$WORK"
  exit 0
fi

# Load AWS credentials if not already set (for non-check-only modes)
if [ -z "${AWS_ACCESS_KEY_ID:-}" ] || [ -z "${AWS_SECRET_ACCESS_KEY:-}" ]; then
  ENV_FILE="$ROOT/.env.secrets"
  if [ -f "$ENV_FILE" ]; then
    set -a
    . "$ENV_FILE"
    set +a
    export AWS_ACCESS_KEY_ID="$NOVA_AWS_ACCESS_KEY_ID"
    export AWS_SECRET_ACCESS_KEY="$NOVA_AWS_SECRET_ACCESS_KEY"
    export AWS_DEFAULT_REGION="$AWS_DEFAULT_REGION"
  fi
fi

echo ""
echo "=== CODEGEN OK ==="
echo "Terraform files ready in: $TF_DIR"
echo "WORK_DIR=$WORK"
