from __future__ import annotations

import json
from pathlib import Path

from pymulator.specs.format_cli import compile_vehicle_spec, explode_vehicle_spec


def _kwp_fixture() -> dict:
    fixture = Path(__file__).resolve().parent / "fixtures" / "kwp.json"
    return json.loads(fixture.read_text(encoding="utf-8"))


def test_compile_project_directory_to_standalone_vehicle(tmp_path: Path) -> None:
    kwp = _kwp_fixture()
    project_dir = tmp_path / "scania.vehicleproj"
    ecus_dir = project_dir / "ecus"
    ecus_dir.mkdir(parents=True, exist_ok=True)
    ecu_path = ecus_dir / "engine.json"
    ecu_path.write_text(json.dumps(kwp), encoding="utf-8")
    manifest = {
        "formatVersion": 2,
        "name": "Scania Project",
        "vin": "YS2R6X40005412735",
        "bus": {"mode": "virtual", "bitrate": 500000, "timingFactor": 0},
        "ecus": [{"name": "POWERTRAIN", "path": "ecus/engine.json"}],
    }
    (project_dir / "vehicle.vehicle").write_text(json.dumps(manifest), encoding="utf-8")

    output_path = compile_vehicle_spec(
        str(project_dir), output=str(tmp_path / "compiled.vehicle"), overwrite=True
    )
    payload = json.loads(output_path.read_text(encoding="utf-8"))

    assert output_path.name == "compiled.vehicle"
    assert payload["formatVersion"] == 2
    assert payload["name"] == "Scania Project"
    assert len(payload["ecus"]) == 1
    assert payload["ecus"][0]["kind"] == "kwp"
    assert payload["ecus"][0]["role"] == "POWERTRAIN"
    assert "path" not in payload["ecus"][0]


def test_explode_standalone_vehicle_to_project_directory(tmp_path: Path) -> None:
    kwp = _kwp_fixture()
    standalone = {
        "formatVersion": 2,
        "name": "Standalone Vehicle",
        "vin": "YS2R6X40005412735",
        "bus": {"mode": "virtual", "bitrate": 500000, "timingFactor": 0},
        "ecus": [{"role": "POWERTRAIN", **kwp}],
    }
    source_path = tmp_path / "standalone.vehicle"
    source_path.write_text(json.dumps(standalone), encoding="utf-8")

    result = explode_vehicle_spec(
        str(source_path), output_dir=str(tmp_path / "out.vehicleproj"), overwrite=True
    )
    manifest_path = result.vehicle_path
    manifest = json.loads(manifest_path.read_text(encoding="utf-8"))

    assert result.ecu_count == 1
    assert manifest_path.name == "vehicle.vehicle"
    assert manifest["formatVersion"] == 2
    assert len(manifest["ecus"]) == 1
    assert manifest["ecus"][0]["name"] == "POWERTRAIN"
    ecu_file = result.output_dir / manifest["ecus"][0]["path"]
    ecu_payload = json.loads(ecu_file.read_text(encoding="utf-8"))
    assert ecu_payload["kind"] == "kwp"
    assert "role" not in ecu_payload


def test_compile_legacy_single_ecu_file_to_vehicle(tmp_path: Path) -> None:
    kwp = _kwp_fixture()
    source_path = tmp_path / "legacy-kwp.json"
    source_path.write_text(json.dumps(kwp), encoding="utf-8")

    output_path = compile_vehicle_spec(
        str(source_path), output=str(tmp_path / "legacy.vehicle"), overwrite=True
    )
    payload = json.loads(output_path.read_text(encoding="utf-8"))

    assert payload["formatVersion"] == 2
    assert len(payload["ecus"]) == 1
    assert payload["ecus"][0]["kind"] == "kwp"


def test_compile_ui_shaped_kwp_normalizes_timing_parameters(tmp_path: Path) -> None:
    kwp = _kwp_fixture()["kwp"]
    kwp_inline = {key: value for key, value in kwp.items() if key != "arbitration"}
    kwp_inline["timingParameters"] = [25.0, 5000.0, 0.5]

    source_payload = {
        "formatVersion": 2,
        "name": "UI-shaped vehicle",
        "vin": "YS2R6X40005412735",
        "ecus": [
            {
                "role": "POWERTRAIN",
                "protocol": "kwp",
                "arbitration": {
                    "requestId": 0x18DA00F9,
                    "replyId": 0x18DAF900,
                },
                "kwp": kwp_inline,
            }
        ],
    }
    source_path = tmp_path / "ui.vehicle"
    source_path.write_text(json.dumps(source_payload), encoding="utf-8")

    output_path = compile_vehicle_spec(
        str(source_path), output=str(tmp_path / "normalized.vehicle"), overwrite=True
    )
    payload = json.loads(output_path.read_text(encoding="utf-8"))
    inline = payload["ecus"][0]

    assert inline["kind"] == "kwp"
    assert inline["kwp"]["timingParameters"] == [0x01, 0xFF, 0x01]
    assert inline["kwp"]["arbitration"]["request"] == 0x18DA00F9
    assert inline["kwp"]["arbitration"]["reply"] == 0x18DAF900
