"""D-2 MFA (TOTP) 테스트"""
import sys, ast, os

os.environ.setdefault("GUARDIA_SECRET_KEY", "test-mfa-secret-key-32bytes-pad!!")
os.environ.setdefault("DATABASE_URL", "sqlite+aiosqlite:///./test_d2.db")

# ── 1. 구문 검사 ─────────────────────────────────────────────────────────────
print("=== 1. 구문 검사 ===")
files = ["core/mfa.py", "routers/auth.py", "models.py"]
ok = True
for f in files:
    try:
        with open(f, encoding="utf-8") as fh:
            src = fh.read()
        ast.parse(src)
        print(f"  OK  {f}")
    except SyntaxError as e:
        print(f"  ERR {f}: {e}")
        ok = False
if not ok:
    sys.exit(1)

# ── 2. AES-GCM 암호화/복호화 라운드트립 ─────────────────────────────────────
print("\n=== 2. AES-GCM 암호화/복호화 테스트 ===")
from core.mfa import (
    generate_totp_secret,
    get_totp_uri,
    verify_totp,
    generate_qr_base64,
    encrypt_totp_secret,
    decrypt_totp_secret,
    create_mfa_pending_token,
    verify_mfa_pending_token,
    _verify_totp_fallback,
)

secret = generate_totp_secret()
print(f"  OK  generate_totp_secret: {secret[:8]}... (len={len(secret)})")

enc = encrypt_totp_secret(secret)
dec = decrypt_totp_secret(enc)
assert dec == secret, f"복호화 실패: {dec!r} != {secret!r}"
print(f"  OK  AES-GCM 암호화/복호화 라운드트립")

# 다른 시크릿과 다른지 확인
enc2 = encrypt_totp_secret(secret)
assert enc != enc2, "동일 평문이 항상 다른 ciphertext 생성 (nonce 랜덤화)"
print(f"  OK  랜덤 nonce로 매번 다른 ciphertext 생성")

# ── 3. TOTP URI 생성 ─────────────────────────────────────────────────────────
print("\n=== 3. TOTP URI 생성 테스트 ===")
uri = get_totp_uri("test_user", secret)
assert "otpauth://totp/" in uri, f"URI 포맷 오류: {uri[:60]}"
assert "GUARDiA" in uri or "guardia" in uri.lower(), f"issuer 없음: {uri[:80]}"
assert secret in uri, "secret 미포함"
print(f"  OK  TOTP URI: {uri[:60]}...")

# ── 4. QR 코드 생성 (옵션) ──────────────────────────────────────────────────
print("\n=== 4. QR 코드 생성 테스트 ===")
qr = generate_qr_base64(uri)
if qr:
    assert len(qr) > 100, "QR base64 너무 짧음"
    print(f"  OK  QR base64 생성 (len={len(qr)})")
else:
    print(f"  INFO  qrcode not installed - QR skip (returns None)")

# ── 5. TOTP 검증 (폴백 함수 사용) ───────────────────────────────────────────
print("\n=== 5. TOTP 검증 테스트 ===")
# 현재 코드 생성 후 검증 (pyotp 있는 경우)
try:
    import pyotp
    totp_obj = pyotp.TOTP(secret)
    current_code = totp_obj.now()
    result = verify_totp(secret, current_code)
    assert result == True, f"현재 코드 검증 실패: {current_code}"
    print(f"  OK  현재 TOTP 코드 검증 성공 (pyotp)")

    # 잘못된 코드
    assert verify_totp(secret, "000000") == False or verify_totp(secret, "000000") == True  # 우연히 맞을 수 있음
    assert verify_totp(secret, "abc123") == False, "비숫자 코드는 무효"
    assert verify_totp(secret, "12345") == False, "5자리는 무효"
    print(f"  OK  잘못된 코드 거부 (형식 검사)")
except ImportError:
    print(f"  INFO  pyotp not installed - using fallback")
    # 폴백은 실제 코드 없이 테스트 불가 (시간 기반)
    assert verify_totp(secret, "abc123") == False
    print(f"  OK  잘못된 코드 거부 (폴백)")

# ── 6. MFA 대기 토큰 발급/검증 ──────────────────────────────────────────────
print("\n=== 6. MFA 대기 토큰 테스트 ===")
mfa_token = create_mfa_pending_token("alice")
assert mfa_token, "토큰 생성 실패"
print(f"  OK  MFA 대기 토큰 생성: {mfa_token[:20]}...")

username = verify_mfa_pending_token(mfa_token)
assert username == "alice", f"사용자 추출 실패: {username}"
print(f"  OK  MFA 대기 토큰 검증: sub={username}")

# 일반 access_token은 mfa_pending 토큰으로 거부
from core.auth import create_access_token
normal_token = create_access_token({"sub": "alice", "role": "ENGINEER"})
assert verify_mfa_pending_token(normal_token) is None, "일반 토큰이 mfa_pending으로 통과됨!"
print(f"  OK  일반 access_token은 mfa_pending 검증 거부")

# 위조된 토큰 거부
assert verify_mfa_pending_token("invalid.token.here") is None
print(f"  OK  위조 토큰 거부")

# ── 7. models.py User 컬럼 확인 ─────────────────────────────────────────────
print("\n=== 7. User 모델 MFA 컬럼 확인 ===")
from models import User, UserOut
cols = {c.key for c in User.__table__.columns}
for col in ["mfa_enabled", "totp_secret_enc"]:
    status = "OK" if col in cols else "ERR"
    print(f"  {status}  User.{col}")
    if status == "ERR":
        ok = False

out_fields = UserOut.model_fields
status = "OK" if "mfa_enabled" in out_fields else "ERR"
print(f"  {status}  UserOut.mfa_enabled")

# ── 8. routers/auth.py 엔드포인트 확인 ─────────────────────────────────────
print("\n=== 8. auth.py MFA 엔드포인트 확인 ===")
with open("routers/auth.py", encoding="utf-8") as f:
    auth_src = f.read()

endpoints = [
    ("/mfa/setup",      "mfa_setup"),
    ("/mfa/enable",     "mfa_enable"),
    ("/mfa/disable",    "mfa_disable"),
    ("/mfa/status",     "mfa_status"),
    ("/login/mfa",      "login_mfa"),
    ("/admin/users",    "admin_mfa_reset"),
]
for path, fn in endpoints:
    status = "OK" if path in auth_src and fn in auth_src else "ERR"
    print(f"  {status}  {path} ({fn})")

print("\n=== 테스트 완료: D-2 MFA (TOTP) ===")
if ok:
    print("모든 검사 통과")
else:
    sys.exit(1)
