"""Tests for ``mil`` unit support across position/coordinate commands.

KiCad natively understands mils (1 mil = 0.0254 mm = 25 400 nm). The MCP
server now accepts ``"mil"`` as a value of the ``unit`` field everywhere a
position or coordinate is specified. Tests below assert:

  - The ``unit→nanometer`` scale used in command handlers maps mil → 25 400.
  - The IPC handler converts mil positions to mm before calling the IPC API.
  - The Python tool schema enums include ``"mil"`` (it was previously
    restricted to ``["mm", "inch"]``).
"""

import sys
from pathlib import Path
from typing import Any
from unittest.mock import MagicMock, patch

import pytest

sys.path.insert(0, str(Path(__file__).parent.parent / "python"))

# Scale used by the per-command handlers when they convert position values
# to KiCad internal nanometers.
MIL_TO_NM = 25_400
MM_TO_NM = 1_000_000
INCH_TO_NM = 25_400_000


def _scale(unit: str) -> int:
    """Mirror of the inline ternary used in commands/* for position scaling."""
    return 1_000_000 if unit == "mm" else (25_400 if unit == "mil" else 25_400_000)


def test_scale_mapping_includes_mil():
    assert _scale("mm") == MM_TO_NM
    assert _scale("mil") == MIL_TO_NM
    assert _scale("inch") == INCH_TO_NM


def test_one_thousand_mil_equals_one_inch_in_nm():
    """Sanity check: 1000 mil should produce the same nm offset as 1 inch."""
    one_inch = 1 * _scale("inch")
    one_thousand_mil = 1000 * _scale("mil")
    assert one_inch == one_thousand_mil


def _make_iface() -> Any:
    with patch("kicad_interface.USE_IPC_BACKEND", True):
        from kicad_interface import KiCADInterface

        iface = KiCADInterface.__new__(KiCADInterface)
    iface.use_ipc = True
    iface.board = None
    iface.ipc_board_api = MagicMock()
    iface.ipc_board_api.place_component.return_value = True
    iface.ipc_board_api.move_component.return_value = True
    return iface


def test_ipc_place_component_converts_mil_to_mm():
    iface = _make_iface()
    iface._ipc_place_component(
        {
            "reference": "R1",
            "footprint": "Resistor_SMD:R_0805",
            "position": {"x": 100, "y": 200, "unit": "mil"},
            "rotation": 0,
            "layer": "F.Cu",
            "value": "220",
        }
    )
    _, kwargs = iface.ipc_board_api.place_component.call_args
    assert kwargs["x"] == pytest.approx(2.54)
    assert kwargs["y"] == pytest.approx(5.08)


def test_ipc_move_component_converts_mil_to_mm():
    iface = _make_iface()
    iface._ipc_move_component({"reference": "R1", "position": {"x": 1000, "y": 500, "unit": "mil"}})
    _, kwargs = iface.ipc_board_api.move_component.call_args
    assert kwargs["x"] == pytest.approx(25.4)
    assert kwargs["y"] == pytest.approx(12.7)


def test_python_tool_schema_unit_enums_include_mil():
    """Every unit enum in TOOL_SCHEMAS must include mil."""
    from schemas.tool_schemas import TOOL_SCHEMAS

    def _find_unit_enums(node):
        """Walk the schema and yield every enum list found under 'unit' fields."""
        if isinstance(node, dict):
            for k, v in node.items():
                if k == "unit" and isinstance(v, dict) and "enum" in v:
                    yield v["enum"]
                else:
                    yield from _find_unit_enums(v)
        elif isinstance(node, list):
            for item in node:
                yield from _find_unit_enums(item)

    enums = list(_find_unit_enums(TOOL_SCHEMAS))
    assert enums, "Expected at least one unit enum in TOOL_SCHEMAS"
    for enum in enums:
        assert "mil" in enum, f"Unit enum {enum} is missing 'mil'"
        # Sanity: mm and inch should still be present too
        assert "mm" in enum and "inch" in enum, f"Unit enum {enum} is malformed"
