"""AutoPOE2 - Closed-Loop Motion Integrity & Hardware Fallback Test Suite (Doc 69 / SSoT 2026).
===========================================================================================
Domain: Sư đoàn 4: LEAD_QA_GOVERNANCE (Quản trị chất lượng & Bất biến).
Kiểm thử bất biến cốt lõi: INV-MOTION-INTEGRITY
- Xác nhận Delta XYZ > 0 (RAM Telemetry) HOẶC Delta Optical > 15px (Vision Optical Flow).
- Phát hiện nhân vật tê liệt ngoài thực địa (Delta XYZ == 0 và Delta Optical <= 15px sau WASD >= 300ms).
- Kích hoạt cơ chế Fail-Closed (ARS = 0.0%) và Hardware Fallback (Release keys, Refocus, Radial Nudge).
- Triệt tiêu hoàn toàn căn bệnh "Green Tests, Dead Product" và báo cáo tiến độ ảo.
"""

from __future__ import annotations

import os
import shutil
import tempfile
from unittest.mock import MagicMock, patch

import pytest

from src.agentic_engine.master_invariants_sentinel import (
    InvariantStatus,
    MasterInvariantsSentinel,
)
from tools.autonomous_mapping_coordinator import AutonomousMappingCoordinator


@pytest.fixture
def sentinel_env():
    """Tạo môi trường cô lập cho Sentinel."""
    temp_dir = tempfile.mkdtemp(prefix="motion_sentinel_test_")
    incidents_dir = os.path.join(temp_dir, "incidents")
    pointer_file = os.path.join(temp_dir, "LATEST_INCIDENT.json")

    sentinel = MasterInvariantsSentinel(
        incidents_dir=incidents_dir,
        latest_pointer_file=pointer_file,
    )

    yield {
        "temp_dir": temp_dir,
        "incidents_dir": incidents_dir,
        "pointer_file": pointer_file,
        "sentinel": sentinel,
    }

    shutil.rmtree(temp_dir, ignore_errors=True)


class TestMotionIntegritySentinel:
    """Kiểm tra logic thẩm định bất biến INV-MOTION-INTEGRITY của MasterInvariantsSentinel."""

    def test_motion_integrity_passes_with_positive_ram_displacement(self, sentinel_env):
        """Trường hợp 1: Nhân vật di chuyển thực tế qua RAM Telemetry (Delta XYZ > 0) -> PASSED."""
        sentinel: MasterInvariantsSentinel = sentinel_env["sentinel"]
        res = sentinel.audit_inv_motion_integrity(
            delta_xyz=18.5,
            delta_optical_px=0.0,
            dwell_ms=450.0,
            wasd_sent=True,
        )

        assert res.status == InvariantStatus.PASSED
        assert res.code == "INV-MOTION-INTEGRITY"
        assert "Delta XYZ=18.5u > 0" in res.evidence

    def test_motion_integrity_passes_with_positive_optical_displacement(self, sentinel_env):
        """Trường hợp 2: Telemetry RAM trễ nhưng Camera quang học phát hiện thay đổi > 15px -> PASSED."""
        sentinel: MasterInvariantsSentinel = sentinel_env["sentinel"]
        res = sentinel.audit_inv_motion_integrity(
            delta_xyz=0.0,
            delta_optical_px=32.0,
            dwell_ms=450.0,
            wasd_sent=True,
        )

        assert res.status == InvariantStatus.PASSED
        assert res.code == "INV-MOTION-INTEGRITY"
        assert "Delta Optical=32.0px > 15px" in res.evidence

    def test_motion_integrity_blocks_when_paralyzed_fail_closed(self, sentinel_env):
        """Trường hợp 3: Nhân vật tê liệt hoàn toàn (Delta XYZ == 0 VÀ Delta Optical <= 15) -> BLOCKED (Fail-Closed)."""
        sentinel: MasterInvariantsSentinel = sentinel_env["sentinel"]
        res = sentinel.audit_inv_motion_integrity(
            delta_xyz=0.0,
            delta_optical_px=0.0,
            dwell_ms=450.0,
            wasd_sent=True,
            hardware_fallback_triggered=False,
        )

        assert res.status == InvariantStatus.BLOCKED
        assert "VI PHẠM NGHIÊM TRỌNG" in res.evidence
        assert "nhân vật tê liệt hoàn toàn" in res.evidence

        # Xác nhận kéo sập ARS về 0.0% khi audit toàn bộ hệ thống
        report = sentinel.audit_all_invariants(custom_overrides={"INV-MOTION-INTEGRITY": False})
        assert report.is_cleared_for_autonomous is False
        assert report.blocked_count >= 1
        assert report.autonomy_readiness_score == 0.0

    def test_motion_integrity_packages_incident_dossier_on_paralysis(self, sentinel_env):
        """Trường hợp 4: Khi xảy ra vi phạm tê liệt, tự động đóng gói hồ sơ sự cố 6 thành phần."""
        sentinel: MasterInvariantsSentinel = sentinel_env["sentinel"]

        dossier_path = sentinel.package_invariant_incident(
            invariant_code="INV-MOTION-INTEGRITY",
            message="Nhân vật cấp 90 đứng yên tại Hideout: Delta XYZ=0.0u sau nhịp WASD 1500ms!",
            telemetry={
                "player": {"hp": 1, "es": 4284, "pos_x": 100.0, "pos_y": 200.0, "pos_z": 0.0},
                "wasd_dwell_ms": 1500,
                "delta_xyz": 0.0,
                "delta_optical_px": 0.0,
            },
            rca_notes={
                "step1_trace": "Phát hiện lệnh WASD được gửi xuống nhưng DirectInput bị DirectX 12 bỏ qua.",
                "step2_invariant": "Vi phạm INV-MOTION-INTEGRITY: delta_xyz == 0.",
                "step3_refactor": "Kích hoạt closed-loop verification và Hardware Fallback trong send_wasd_direction.",
                "step4_lock": "Khóa chặn bằng unit test test_motion_integrity.py.",
            },
        )

        assert os.path.exists(dossier_path)
        incident_dir = os.path.dirname(dossier_path)
        assert os.path.exists(os.path.join(incident_dir, "incident_dossier.json"))
        assert os.path.exists(os.path.join(incident_dir, "RCA_4_STEPS_ANALYSIS.md"))


class TestCoordinatorMotionIntegrityIntegration:
    """Kiểm tra tích hợp INV-MOTION-INTEGRITY vào AutonomousMappingCoordinator."""

    def test_coordinator_verify_motion_integrity_positive(self):
        """Xác nhận verify_motion_integrity trả về True khi có dịch chuyển tọa độ."""
        coord = AutonomousMappingCoordinator(is_simulated=True)
        pos0 = (100.0, 100.0)
        pos1 = (115.0, 105.0)

        assert coord.verify_motion_integrity(pos0, pos1, optical_delta_px=0.0) is True

    def test_coordinator_verify_motion_integrity_triggers_hardware_fallback_on_paralysis(self):
        """Xác nhận verify_motion_integrity kích hoạt trigger_hardware_motion_fallback khi tê liệt."""
        coord = AutonomousMappingCoordinator(is_simulated=True)
        coord.trigger_hardware_motion_fallback = MagicMock()

        pos0 = (100.0, 100.0)
        pos1 = (100.0, 100.0)  # Delta == 0!

        res = coord.verify_motion_integrity(pos0, pos1, optical_delta_px=5.0, dwell_ms=500.0)
        assert res is False
        assert coord.trigger_hardware_motion_fallback.call_count == 1

    def test_coordinator_send_wasd_direction_performs_closed_loop_check_in_live_mode(self):
        """Xác nhận send_wasd_direction trong live mode (is_simulated=False) đọc tọa độ và kiểm tra closed-loop."""
        coord = AutonomousMappingCoordinator(is_simulated=False)
        coord.ensure_focus = MagicMock(return_value=True)

        positions = [(100.0, 100.0), (120.0, 100.0)]
        coord.get_player_world_pos = MagicMock(side_effect=positions)
        coord.verify_motion_integrity = MagicMock(return_value=True)

        with patch("src.common.is_poe2_window_focused", return_value=True), \
             patch("src.common.send_wasd_direction", return_value=True):
            ok = coord.send_wasd_direction(1.0, 0.0, dwell_ms=0.45)

        assert ok is True
        assert coord.get_player_world_pos.call_count == 2
        assert coord.verify_motion_integrity.call_count == 1
        args, kwargs = coord.verify_motion_integrity.call_args
        assert args[0] == (100.0, 100.0)
        assert args[1] == (120.0, 100.0)
