"""
Unit tests cho AutoPOE2 Process Supervisor Engine (tools/poe2_supervisor.py)
Kiểm chứng:
1. Shadow Binary Execution & Hash sync
2. Grounded Status Reporting (Anti-Hallucination)
3. HTTP Control Plane (/status, /pause, /resume)
"""

import sys
import json
import time
import urllib.request
from pathlib import Path
import pytest

WORKSPACE_ROOT = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(WORKSPACE_ROOT))

from tools.poe2_supervisor import Poe2Supervisor, calculate_sha256


@pytest.fixture
def temp_bins(tmp_path):
    """Tạo tệp nhị phân giả lập để kiểm thử logic shadow binary."""
    source_bin = tmp_path / "AutoPOE2_Core.exe"
    runtime_bin = tmp_path / "AutoPOE2_Core_Runtime.exe"

    # Ghi nội dung giả lập ban đầu
    source_bin.write_bytes(b"MOCK_CORE_BINARY_DATA_V1")
    return source_bin, runtime_bin


def test_sha256_calculation(tmp_path):
    f = tmp_path / "dummy.bin"
    f.write_bytes(b"hello world")
    h = calculate_sha256(f)
    assert len(h) == 64
    assert h == "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9"


def test_prepare_shadow_binary(temp_bins):
    source_bin, runtime_bin = temp_bins
    supervisor = Poe2Supervisor(source_bin=source_bin, runtime_bin=runtime_bin, http_port=18089)

    assert not runtime_bin.exists()
    success = supervisor.prepare_shadow_binary()
    assert success is True
    assert runtime_bin.exists()
    assert runtime_bin.read_bytes() == b"MOCK_CORE_BINARY_DATA_V1"
    assert calculate_sha256(source_bin) == calculate_sha256(runtime_bin)


def test_prepare_shadow_binary_when_synced(temp_bins):
    source_bin, runtime_bin = temp_bins
    supervisor = Poe2Supervisor(source_bin=source_bin, runtime_bin=runtime_bin, http_port=18089)

    supervisor.prepare_shadow_binary()
    mtime1 = runtime_bin.stat().st_mtime

    time.sleep(0.01)
    # Lần 2 không cần copy lại vì hash trùng khớp
    success = supervisor.prepare_shadow_binary(force=False)
    assert success is True
    mtime2 = runtime_bin.stat().st_mtime
    assert mtime1 == mtime2


def test_get_status_grounding(temp_bins):
    source_bin, runtime_bin = temp_bins
    supervisor = Poe2Supervisor(source_bin=source_bin, runtime_bin=runtime_bin, http_port=18089)

    status = supervisor.get_status()
    assert "supervisor" in status
    assert "game_client" in status
    assert "shadow_runtime" in status
    assert "telemetry" in status

    # Kiểm tra tính trung thực của báo cáo
    assert status["shadow_runtime"]["source_exists"] is True
    assert status["shadow_runtime"]["runtime_exists"] is False
    assert status["shadow_runtime"]["running"] is False
    assert isinstance(status["game_client"]["running"], bool)
    assert isinstance(status["game_client"]["pids"], list)


def test_http_control_plane(temp_bins):
    source_bin, runtime_bin = temp_bins
    test_port = 18088
    supervisor = Poe2Supervisor(source_bin=source_bin, runtime_bin=runtime_bin, http_port=test_port)

    try:
        supervisor.start()
        time.sleep(0.5)

        # 1. Test GET /status
        req = urllib.request.Request(f"http://127.0.0.1:{test_port}/status")
        with urllib.request.urlopen(req, timeout=3) as resp:
            assert resp.status == 200
            data = json.loads(resp.read().decode("utf-8"))
            assert data["supervisor"]["active"] is True
            assert data["supervisor"]["http_port"] == test_port

        # 2. Test POST /pause
        req = urllib.request.Request(f"http://127.0.0.1:{test_port}/pause", data=b"{}", headers={"Content-Type": "application/json"})
        with urllib.request.urlopen(req, timeout=3) as resp:
            assert resp.status == 200
            data = json.loads(resp.read().decode("utf-8"))
            assert data["paused"] is True
            assert supervisor._paused is True

        # 4. Test GET /preview (HTML PiP Streamer)
        with urllib.request.urlopen(f"http://127.0.0.1:{test_port}/preview", timeout=3) as resp:
            assert resp.status == 200
            content_type = resp.headers.get("Content-Type", "")
            assert "text/html" in content_type
            html_body = resp.read().decode("utf-8")
            assert "AutoPOE2 Virtual Screen" in html_body
            assert "/preview.jpg" in html_body

        # 5. Test GET /preview.jpg (Live JPEG frame)
        with urllib.request.urlopen(f"http://127.0.0.1:{test_port}/preview.jpg", timeout=3) as resp:
            assert resp.status == 200
            content_type = resp.headers.get("Content-Type", "")
            assert "image/jpeg" in content_type
            jpeg_bytes = resp.read()
            assert len(jpeg_bytes) > 1000
            assert jpeg_bytes[:2] == b"\xff\xd8" # Standard JPEG SOI marker

    finally:
        supervisor.stop()
        time.sleep(0.2)
