#!/usr/bin/env bash
set -u

RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
NC='\033[0m'

ok() { printf "${GREEN}[OK]${NC} %s\n" "$1"; }
warn() { printf "${YELLOW}[WARN]${NC} %s\n" "$1"; }
fail() { printf "${RED}[FAIL]${NC} %s\n" "$1"; }

EXIT_CODE=0

cd "$(dirname "$0")/.." || exit 1

echo "── 1) Verificando estructura base ─────────────────────"
required=(
  "AGENTS.md"
  "CHECKPOINTS.md"
  "README.md"
  "HOWTO.md"
  "TEMPLATE.md"
  "docs/README.md"
  "docs/repository-layout.md"
  "docs/scripts-reference.md"
  "harness/agents.matrix.yml"
  "harness/workflow.stages.yml"
  "harness/policies/governance.md"
  "harness/policies/security.md"
  "harness/policies/quality.md"
  "harness/policies/language.md"
  "harness/policies/model-routing.md"
  "harness/models.profiles.yml"
  "harness/contracts/handoff.md"
  "harness/contracts/evidence.schema.json"
  "spec/product.md"
  "spec/tech.md"
  "spec/acceptance.md"
  "spec/bdd/README.md"
  "spec/bdd/features/README.md"
  "spec/sdd/README.md"
  "spec/sdd/components/README.md"
  "spec/sdd/decisions/README.md"
  "features/README.md"
  "project/README.md"
  "backlog/features.json"
  "work/current.md"
  "work/history.md"
  "work/runtime-status.json"
  "scripts/agent_status.py"
  "scripts/new_ticket.py"
  "scripts/publish_ticket.py"
  "scripts/install_into_repo.sh"
  "scripts/start.sh"
  "platforms/pi/README.md"
  "platforms/opencode/README.md"
)

for f in "${required[@]}"; do
  if [ -f "$f" ]; then
    ok "Existe $f"
  else
    fail "Falta $f"
    EXIT_CODE=1
  fi
done

echo ""
echo "── 1.5) Validando git repo ───────────────────────────"
if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
  ok "Git repo detectado"
  if git remote | grep -q .; then
    ok "Git remote configurado"
  else
    warn "Sin git remote configurado (publish requerirá remote)"
  fi
else
  fail "Este proyecto debe vivir dentro de un git repo"
  EXIT_CODE=1
fi

echo ""
echo "── 2) Validando backlog + gates ───────────────────────"
python3 - <<'PY'
import json
import pathlib
import sys

root = pathlib.Path('.')
path = root / 'backlog' / 'features.json'
level_choices = {'low', 'med', 'high'}

try:
    data = json.loads(path.read_text(encoding='utf-8'))
except Exception as e:
    print(f"[FAIL] backlog/features.json inválido: {e}")
    sys.exit(1)

rules = data.get('rules', {})
valid_status = set(rules.get('valid_status', ["pending", "in_progress", "blocked", "done"]))
valid_types = set(rules.get('valid_types', ["feature", "fix", "bug", "chore"]))
features = data.get('features', [])
if not isinstance(features, list):
    print('[FAIL] features debe ser una lista')
    sys.exit(1)

ids = [str(f.get('id', '')).strip() for f in features]
if len(ids) != len(set(ids)):
    print('[FAIL] Hay IDs de feature duplicados en backlog/features.json')
    sys.exit(1)

in_progress = [f for f in features if f.get('status') == 'in_progress']
if len(in_progress) > 1:
    print(f"[FAIL] Hay {len(in_progress)} features in_progress (máximo 1)")
    sys.exit(1)

for f in features:
    fid = str(f.get('id', '')).strip()
    status = f.get('status')
    title = str(f.get('title', '')).strip()
    acceptance = f.get('acceptance')
    gates = f.get('gates', {})

    if not fid:
        print('[FAIL] Hay una feature sin id')
        sys.exit(1)
    if not title:
        print(f"[FAIL] Feature {fid} sin title")
        sys.exit(1)
    if status not in valid_status:
        print(f"[FAIL] Estado inválido en feature {fid}: {status}")
        sys.exit(1)
    if not isinstance(acceptance, list) or not acceptance or any(not str(item).strip() for item in acceptance):
        print(f"[FAIL] Feature {fid} debe tener acceptance como lista no vacía")
        sys.exit(1)

    ticket_type = f.get('type')
    if ticket_type is not None and ticket_type not in valid_types:
        print(f"[FAIL] Feature {fid} tiene type inválido: {ticket_type}")
        sys.exit(1)

    for field in ('priority', 'risk'):
        value = f.get(field)
        if value is not None and value not in level_choices:
            print(f"[FAIL] Feature {fid} tiene {field} inválido: {value}")
            sys.exit(1)

    for field in ('scope_in', 'scope_out'):
        value = f.get(field)
        if value is not None:
            if not isinstance(value, list) or any(not str(item).strip() for item in value):
                print(f"[FAIL] Feature {fid} tiene {field} inválido")
                sys.exit(1)

    if gates:
        for gate_name in ('review', 'security', 'qa'):
            gate_value = gates.get(gate_name)
            if not isinstance(gate_value, bool):
                print(f"[FAIL] Feature {fid} tiene gates.{gate_name} inválido")
                sys.exit(1)

    if status == 'done':
        d = root / 'work' / 'artifacts' / fid
        req = ['reviewer.json', 'security.json', 'qa.json', 'leader-close.json', 'documenter.md', 'publish.json']
        missing = [name for name in req if not (d / name).is_file()]
        if missing:
            print(f"[FAIL] Feature {fid} done sin artefactos: {', '.join(missing)}")
            sys.exit(1)

        expected = {
            'reviewer.json': ('reviewer', 'APPROVED'),
            'security.json': ('security', 'APPROVED'),
            'qa.json': ('qa', 'APPROVED'),
            'leader-close.json': ('leader', 'APPROVED'),
            'publish.json': ('leader', 'PUBLISHED'),
        }
        for filename, rule in expected.items():
            agent, verdict = rule
            try:
                obj = json.loads((d / filename).read_text(encoding='utf-8'))
            except Exception as e:
                print(f"[FAIL] {fid}/{filename} inválido: {e}")
                sys.exit(1)

            if obj.get('agent') != agent:
                print(f"[FAIL] {fid}/{filename} agent debe ser '{agent}'")
                sys.exit(1)
            if obj.get('verdict') != verdict:
                print(f"[FAIL] {fid}/{filename} no está {verdict}")
                sys.exit(1)
            if filename == 'publish.json' and obj.get('pushed') is not True:
                print(f"[FAIL] {fid}/{filename} debe tener pushed=true")
                sys.exit(1)

print(f"[OK] backlog válido ({len(features)} features)")
PY
if [ $? -ne 0 ]; then EXIT_CODE=1; fi

python3 - <<'PY'
import json
import pathlib
import sys

path = pathlib.Path('work/runtime-status.json')
required = ['feature_id', 'stage', 'agent', 'action', 'state', 'next_agent', 'waiting_for', 'updated_at', 'timeline']
try:
    data = json.loads(path.read_text(encoding='utf-8'))
except Exception as e:
    print(f"[FAIL] work/runtime-status.json inválido: {e}")
    sys.exit(1)

missing = [key for key in required if key not in data]
if missing:
    print(f"[FAIL] work/runtime-status.json incompleto: {', '.join(missing)}")
    sys.exit(1)
if not isinstance(data.get('timeline'), list):
    print('[FAIL] work/runtime-status.json timeline debe ser una lista')
    sys.exit(1)
print('[OK] runtime-status válido')
PY
if [ $? -ne 0 ]; then EXIT_CODE=1; fi

echo ""
echo "── 3) Verificación de tests/build (auto-detect) ───────"
if [ -f "Makefile" ] && grep -qE '^test:' Makefile; then
  if make test; then ok "make test OK"; else fail "make test falló"; EXIT_CODE=1; fi
elif [ -f "package.json" ]; then
  if command -v npm >/dev/null 2>&1; then
    if npm test --silent --if-present; then ok "npm test OK"; else fail "npm test falló"; EXIT_CODE=1; fi
  else
    warn "package.json detectado pero npm no está disponible"
  fi
elif [ -d "tests" ]; then
  if command -v pytest >/dev/null 2>&1; then
    if pytest -q; then ok "pytest OK"; else fail "pytest falló"; EXIT_CODE=1; fi
  else
    if python3 -m unittest discover -s tests -v; then ok "unittest OK"; else fail "unittest falló"; EXIT_CODE=1; fi
  fi
else
  warn "No se detectó suite automática (tests/ | Makefile test | package.json test)"
fi

echo ""
echo "── 4) Overlay local opcional ─────────────────────────"
if [ -x "scripts/verify.local.sh" ]; then
  if ./scripts/verify.local.sh; then
    ok "verify.local.sh OK"
  else
    fail "verify.local.sh falló"
    EXIT_CODE=1
  fi
elif [ -f "scripts/verify.local.sh" ]; then
  warn "scripts/verify.local.sh existe pero no es ejecutable"
else
  warn "Sin overlay local (scripts/verify.local.sh)"
fi

echo ""
echo "── 5) Resumen ─────────────────────────────────────────"
if [ $EXIT_CODE -eq 0 ]; then
  ok "Harness verificado. Template listo para adaptar a cualquier proyecto."
else
  fail "Harness NO verificado. Corrige antes de continuar."
fi

exit $EXIT_CODE
