#!/usr/bin/env python3
"""
Tests for Story 8.02 (Track B): AxiomaticTests — Compiled GLOBAL_GENESIS_RULES Assertions

Black Box tests (BB): verify public contract — axiom violations detected correctly,
    clean inputs pass, all 5 axioms checked independently.
White Box tests (WB): verify internal mechanics — non-fail-fast accumulation,
    empty violations list, AxiomViolation field structure, OCC safe pattern,
    Gemini with auth passes.

Story: 8.02
File under test: core/evolution/axiomatic_tests.py

ALL tests are pure Python — NO external I/O, NO mocks needed, NO network calls.
"""

from __future__ import annotations

import sys
sys.path.insert(0, "/mnt/e/genesis-system")

import pytest

from core.evolution.axiomatic_tests import (
    AxiomaticTests,
    AxiomResult,
    AxiomViolation,
)

# ---------------------------------------------------------------------------
# Shared fixture
# ---------------------------------------------------------------------------

@pytest.fixture()
def checker() -> AxiomaticTests:
    """Fresh AxiomaticTests instance for each test."""
    return AxiomaticTests()


# ===========================================================================
# BLACK BOX TESTS
# ===========================================================================


def test_bb1_sqlite_import_raises_axiom_no_sqlite(checker: AxiomaticTests):
    """BB1: Code containing 'import sqlite3' → AXIOM_NO_SQLITE violation."""
    code = "import sqlite3\nconn = sqlite3.connect(':memory:')"
    result = checker.run_all(code_content=code, state_content={})

    assert result.passed is False
    axiom_ids = [v.axiom_id for v in result.violations]
    assert "AXIOM_NO_SQLITE" in axiom_ids, (
        f"Expected AXIOM_NO_SQLITE in violations, got: {axiom_ids}"
    )


def test_bb2_api_key_in_state_raises_axiom_no_api_key_leak(checker: AxiomaticTests):
    """BB2: State dict containing 'sk-abc123' → AXIOM_NO_API_KEY_LEAK violation."""
    state = {"openai_key": "sk-abc123xyz", "model": "gpt-4"}
    result = checker.run_all(code_content="print('hello')", state_content=state)

    assert result.passed is False
    axiom_ids = [v.axiom_id for v in result.violations]
    assert "AXIOM_NO_API_KEY_LEAK" in axiom_ids, (
        f"Expected AXIOM_NO_API_KEY_LEAK in violations, got: {axiom_ids}"
    )


def test_bb3_clean_code_clean_state_passes(checker: AxiomaticTests):
    """BB3: Clean code + clean state → passed=True, violations=[]."""
    code = (
        "import psycopg2\n"
        "conn = psycopg2.connect(host='elestio.example.com')\n"
        "cur.execute('UPDATE entities SET data=%s WHERE version=1', (data,))\n"
    )
    result = checker.run_all(code_content=code, state_content={"status": "ok"})

    assert result.passed is True, (
        f"Expected passed=True but got violations: {result.violations}"
    )
    assert result.violations == [], (
        f"Expected empty violations, got: {result.violations}"
    )


def test_bb4_insert_without_version_check_raises_occ_required(checker: AxiomaticTests):
    """BB4: Code with INSERT but no 'WHERE version =' → AXIOM_OCC_REQUIRED violation."""
    code = (
        "cur.execute('INSERT INTO sessions (id, data) VALUES (%s, %s)', (sid, data))\n"
    )
    result = checker.run_all(code_content=code, state_content={})

    assert result.passed is False
    axiom_ids = [v.axiom_id for v in result.violations]
    assert "AXIOM_OCC_REQUIRED" in axiom_ids, (
        f"Expected AXIOM_OCC_REQUIRED in violations, got: {axiom_ids}"
    )


def test_bb5_c_drive_path_raises_axiom_no_c_drive(checker: AxiomaticTests):
    """BB5: Code containing 'C:\\Users\\...' path → AXIOM_NO_C_DRIVE violation."""
    code = r"with open('C:\Users\P3\data\output.txt', 'w') as f: f.write(data)"
    result = checker.run_all(code_content=code, state_content={})

    assert result.passed is False
    axiom_ids = [v.axiom_id for v in result.violations]
    assert "AXIOM_NO_C_DRIVE" in axiom_ids, (
        f"Expected AXIOM_NO_C_DRIVE in violations, got: {axiom_ids}"
    )


def test_bb6_gemini_without_auth_raises_axiom_gemini_auth(checker: AxiomaticTests):
    """BB6: Code referencing gemini.google.com without login/auth → AXIOM_GEMINI_AUTH."""
    code = (
        "import requests\n"
        "response = requests.get('https://gemini.google.com/chat')\n"
        "result = response.json()\n"
    )
    result = checker.run_all(code_content=code, state_content={})

    assert result.passed is False
    axiom_ids = [v.axiom_id for v in result.violations]
    assert "AXIOM_GEMINI_AUTH" in axiom_ids, (
        f"Expected AXIOM_GEMINI_AUTH in violations, got: {axiom_ids}"
    )


# ===========================================================================
# WHITE BOX TESTS
# ===========================================================================


def test_wb1_all_5_axioms_checked_not_fail_fast(checker: AxiomaticTests):
    """WB1: Code triggering 3 separate violations → all 3 returned (not fail-fast)."""
    # Triggers: AXIOM_NO_SQLITE, AXIOM_OCC_REQUIRED (INSERT without version), AXIOM_NO_C_DRIVE
    code = (
        "import sqlite3\n"
        "conn = sqlite3.connect('local.db')\n"
        "cur.execute('INSERT INTO logs (msg) VALUES (%s)', (msg,))\n"
        r"path = 'C:\Users\P3\data\output.txt'" + "\n"
    )
    result = checker.run_all(code_content=code, state_content={})

    assert result.passed is False
    assert len(result.violations) >= 3, (
        f"Expected >=3 violations but got {len(result.violations)}: "
        f"{[v.axiom_id for v in result.violations]}"
    )
    axiom_ids = {v.axiom_id for v in result.violations}
    assert "AXIOM_NO_SQLITE" in axiom_ids
    assert "AXIOM_OCC_REQUIRED" in axiom_ids
    assert "AXIOM_NO_C_DRIVE" in axiom_ids


def test_wb2_violations_is_empty_list_not_none_when_passing(checker: AxiomaticTests):
    """WB2: When all axioms pass, violations is [] (not None, not other falsy)."""
    result = checker.run_all(code_content="x = 1", state_content={})

    assert result.passed is True
    assert result.violations is not None
    assert isinstance(result.violations, list)
    assert len(result.violations) == 0


def test_wb3_axiom_violation_has_all_three_fields(checker: AxiomaticTests):
    """WB3: AxiomViolation dataclass exposes axiom_id, description, evidence fields."""
    code = "import sqlite3"
    result = checker.run_all(code_content=code, state_content={})

    assert result.violations, "Expected at least one violation"
    violation = result.violations[0]

    # All three required fields must exist and be non-empty strings
    assert hasattr(violation, "axiom_id"), "AxiomViolation missing 'axiom_id'"
    assert hasattr(violation, "description"), "AxiomViolation missing 'description'"
    assert hasattr(violation, "evidence"), "AxiomViolation missing 'evidence'"

    assert isinstance(violation.axiom_id, str) and violation.axiom_id
    assert isinstance(violation.description, str) and violation.description
    assert isinstance(violation.evidence, str) and violation.evidence


def test_wb4_insert_with_version_check_does_not_trigger_occ_violation(checker: AxiomaticTests):
    """WB4: UPDATE with 'WHERE version =' present → no AXIOM_OCC_REQUIRED violation."""
    code = (
        "cur.execute(\n"
        "    'UPDATE sessions SET data=%s WHERE version=%s',\n"
        "    (data, version)\n"
        ")\n"
    )
    result = checker.run_all(code_content=code, state_content={})

    axiom_ids = [v.axiom_id for v in result.violations]
    assert "AXIOM_OCC_REQUIRED" not in axiom_ids, (
        f"AXIOM_OCC_REQUIRED should not trigger when 'WHERE version =' is present. "
        f"Got violations: {axiom_ids}"
    )


def test_wb5_gemini_with_login_does_not_trigger_gemini_auth_violation(checker: AxiomaticTests):
    """WB5: Code with gemini.google.com AND 'login' → no AXIOM_GEMINI_AUTH violation."""
    code = (
        "# Navigate to Gemini and login\n"
        "driver.get('https://gemini.google.com')\n"
        "login_button = driver.find_element(By.ID, 'login')\n"
        "login_button.click()\n"
    )
    result = checker.run_all(code_content=code, state_content={})

    axiom_ids = [v.axiom_id for v in result.violations]
    assert "AXIOM_GEMINI_AUTH" not in axiom_ids, (
        f"AXIOM_GEMINI_AUTH should not trigger when 'login' is present. "
        f"Got violations: {axiom_ids}"
    )


def test_wb6_gemini_with_auth_keyword_does_not_trigger_gemini_auth_violation(
    checker: AxiomaticTests,
):
    """WB6 (extra): gemini.google.com + 'auth' in code → no AXIOM_GEMINI_AUTH violation."""
    code = (
        "# Ensure authenticated session before accessing Gemini\n"
        "auth_token = get_auth_token()\n"
        "url = 'https://gemini.google.com/chat'\n"
        "headers = {'Authorization': f'Bearer {auth_token}'}\n"
    )
    result = checker.run_all(code_content=code, state_content={})

    axiom_ids = [v.axiom_id for v in result.violations]
    assert "AXIOM_GEMINI_AUTH" not in axiom_ids, (
        f"AXIOM_GEMINI_AUTH should not trigger when 'auth' is present. "
        f"Got violations: {axiom_ids}"
    )


# ===========================================================================
# Additional edge-case / contract tests
# ===========================================================================


def test_api_key_in_state_telnyx_pattern_detected(checker: AxiomaticTests):
    """TELNYX_API_KEY pattern in state dict triggers AXIOM_NO_API_KEY_LEAK."""
    state = {"env": {"TELNYX_API_KEY": "KEY_secret123"}}
    result = checker.run_all(code_content="pass", state_content=state)

    axiom_ids = [v.axiom_id for v in result.violations]
    assert "AXIOM_NO_API_KEY_LEAK" in axiom_ids


def test_api_key_in_state_api_key_equals_pattern_detected(checker: AxiomaticTests):
    """'API_KEY=' pattern in state dict triggers AXIOM_NO_API_KEY_LEAK."""
    state = {"config": "API_KEY=supersecret", "region": "us-east-1"}
    result = checker.run_all(code_content="pass", state_content=state)

    axiom_ids = [v.axiom_id for v in result.violations]
    assert "AXIOM_NO_API_KEY_LEAK" in axiom_ids


def test_c_drive_forward_slash_pattern_detected(checker: AxiomaticTests):
    """'C:/' (forward slash) path triggers AXIOM_NO_C_DRIVE."""
    code = "output = open('C:/Users/P3/output.csv', 'w')"
    result = checker.run_all(code_content=code, state_content={})

    axiom_ids = [v.axiom_id for v in result.violations]
    assert "AXIOM_NO_C_DRIVE" in axiom_ids


def test_axiom_result_is_dataclass_with_passed_and_violations(checker: AxiomaticTests):
    """AxiomResult has 'passed' (bool) and 'violations' (list) fields."""
    result = checker.run_all(code_content="x = 42", state_content={})

    assert hasattr(result, "passed")
    assert hasattr(result, "violations")
    assert isinstance(result.passed, bool)
    assert isinstance(result.violations, list)


def test_import_sqlite_bare_token_detected(checker: AxiomaticTests):
    """'sqlite3' as a bare token (not import statement) still triggers AXIOM_NO_SQLITE."""
    code = "conn = sqlite3.connect(':memory:')  # using sqlite3 directly"
    result = checker.run_all(code_content=code, state_content={})

    axiom_ids = [v.axiom_id for v in result.violations]
    assert "AXIOM_NO_SQLITE" in axiom_ids


def test_occ_check_case_insensitive_insert(checker: AxiomaticTests):
    """Lowercase 'insert into' (no WHERE version=) also triggers AXIOM_OCC_REQUIRED."""
    code = "cur.execute('insert into events (name) values (%s)', (name,))"
    result = checker.run_all(code_content=code, state_content={})

    axiom_ids = [v.axiom_id for v in result.violations]
    assert "AXIOM_OCC_REQUIRED" in axiom_ids


def test_update_with_where_version_equals_space_variant(checker: AxiomaticTests):
    """'WHERE version = 5' (space before =) correctly satisfies OCC check."""
    code = "UPDATE sessions SET state = %s WHERE version = 5"
    result = checker.run_all(code_content=code, state_content={})

    axiom_ids = [v.axiom_id for v in result.violations]
    assert "AXIOM_OCC_REQUIRED" not in axiom_ids


# ===========================================================================
# Standalone runner
# ===========================================================================

if __name__ == "__main__":
    import traceback

    _checker = AxiomaticTests()
    tests = [
        ("BB1: import sqlite3 → AXIOM_NO_SQLITE",
         lambda: test_bb1_sqlite_import_raises_axiom_no_sqlite(_checker)),
        ("BB2: sk-xxx in state → AXIOM_NO_API_KEY_LEAK",
         lambda: test_bb2_api_key_in_state_raises_axiom_no_api_key_leak(_checker)),
        ("BB3: clean code + clean state → passed=True",
         lambda: test_bb3_clean_code_clean_state_passes(_checker)),
        ("BB4: INSERT without WHERE version → AXIOM_OCC_REQUIRED",
         lambda: test_bb4_insert_without_version_check_raises_occ_required(_checker)),
        ("BB5: C:\\Users path → AXIOM_NO_C_DRIVE",
         lambda: test_bb5_c_drive_path_raises_axiom_no_c_drive(_checker)),
        ("BB6: gemini.google.com no auth → AXIOM_GEMINI_AUTH",
         lambda: test_bb6_gemini_without_auth_raises_axiom_gemini_auth(_checker)),
        ("WB1: 3 violations all returned (not fail-fast)",
         lambda: test_wb1_all_5_axioms_checked_not_fail_fast(_checker)),
        ("WB2: violations=[] (not None) when passing",
         lambda: test_wb2_violations_is_empty_list_not_none_when_passing(_checker)),
        ("WB3: AxiomViolation has all 3 fields",
         lambda: test_wb3_axiom_violation_has_all_three_fields(_checker)),
        ("WB4: INSERT + WHERE version= → no AXIOM_OCC_REQUIRED",
         lambda: test_wb4_insert_with_version_check_does_not_trigger_occ_violation(_checker)),
        ("WB5: gemini.google.com + login → no AXIOM_GEMINI_AUTH",
         lambda: test_wb5_gemini_with_login_does_not_trigger_gemini_auth_violation(_checker)),
        ("WB6: gemini.google.com + auth keyword → no AXIOM_GEMINI_AUTH",
         lambda: test_wb6_gemini_with_auth_keyword_does_not_trigger_gemini_auth_violation(_checker)),
        ("EDGE: TELNYX_API_KEY in state → AXIOM_NO_API_KEY_LEAK",
         lambda: test_api_key_in_state_telnyx_pattern_detected(_checker)),
        ("EDGE: API_KEY= in state → AXIOM_NO_API_KEY_LEAK",
         lambda: test_api_key_in_state_api_key_equals_pattern_detected(_checker)),
        ("EDGE: C:/ forward slash → AXIOM_NO_C_DRIVE",
         lambda: test_c_drive_forward_slash_pattern_detected(_checker)),
        ("EDGE: AxiomResult has passed + violations fields",
         lambda: test_axiom_result_is_dataclass_with_passed_and_violations(_checker)),
        ("EDGE: bare sqlite3 token → AXIOM_NO_SQLITE",
         lambda: test_import_sqlite_bare_token_detected(_checker)),
        ("EDGE: lowercase insert without version → AXIOM_OCC_REQUIRED",
         lambda: test_occ_check_case_insensitive_insert(_checker)),
        ("EDGE: WHERE version = 5 space variant → no AXIOM_OCC_REQUIRED",
         lambda: test_update_with_where_version_equals_space_variant(_checker)),
    ]

    passed = 0
    total = len(tests)
    for name, fn in tests:
        try:
            fn()
            print(f"  [PASS] {name}")
            passed += 1
        except Exception as exc:
            print(f"  [FAIL] {name}: {exc}")
            traceback.print_exc()

    print(f"\n{passed}/{total} tests passed")
    if passed == total:
        print("ALL TESTS PASSED -- Story 8.02 (Track B)")
    else:
        sys.exit(1)
