from __future__ import annotations

import sys
from pathlib import Path

# Allow importing from src/ without installing
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT / "src"))


def _write(p: Path, text: str) -> None:
    p.write_text(text, encoding="utf-8")


def _read(p: Path) -> str:
    return p.read_text(encoding="utf-8")


def test_xs2x_orthorhombic(tmp_path: Path) -> None:
    import reacnet_md_tools.xs2x as xs2x

    inp = tmp_path / "in.lammpstrj"
    out = tmp_path / "out.lammpstrj"

    _write(
        inp,
        """ITEM: TIMESTEP
0
ITEM: NUMBER OF ATOMS
2
ITEM: BOX BOUNDS pp pp pp
0 10
0 10
0 10
ITEM: ATOMS id type xs ys zs
1 1 0.0 0.5 1.0
2 1 0.25 0.25 0.25
""",
    )

    xs2x.main(["-i", str(inp), "-o", str(out), "--precision", "8"])
    txt = _read(out)

    assert "ITEM: ATOMS id type x y z" in txt
    assert "1 1 0.00000000 5.00000000 10.00000000" in txt
    assert "2 1 2.50000000 2.50000000 2.50000000" in txt


def test_xs2x_triclinic_simple(tmp_path: Path) -> None:
    import reacnet_md_tools.xs2x as xs2x

    inp = tmp_path / "in_tri.lammpstrj"
    out = tmp_path / "out_tri.lammpstrj"

    # Triclinic bounds with tilts:
    # x: lo hi xy
    # y: lo hi xz
    # z: lo hi yz
    _write(
        inp,
        """ITEM: TIMESTEP
0
ITEM: NUMBER OF ATOMS
2
ITEM: BOX BOUNDS xy xz yz pp pp pp
0 10 1
0 10 2
0 10 3
ITEM: ATOMS id type xs ys zs
1 1 0.0 0.5 1.0
2 1 0.25 0.25 0.25
""",
    )

    xs2x.main(["-i", str(inp), "-o", str(out), "--precision", "8"])
    txt = _read(out)

    # Expected values derived from LAMMPS triclinic h-matrix mapping.
    assert "ITEM: ATOMS id type x y z" in txt
    assert "1 1 2.50000000 6.50000000 10.00000000" in txt
    assert "2 1 2.50000000 2.50000000 2.50000000" in txt


def test_xs2x_triclinic_negative_tilts(tmp_path: Path) -> None:
    import reacnet_md_tools.xs2x as xs2x

    inp = tmp_path / "in_tri_neg.lammpstrj"
    out = tmp_path / "out_tri_neg.lammpstrj"

    _write(
        inp,
        """ITEM: TIMESTEP
0
ITEM: NUMBER OF ATOMS
1
ITEM: BOX BOUNDS xy xz yz pp pp pp
-5 5 -2
-5 5 1
-5 5 -3
ITEM: ATOMS id type xs ys zs
1 1 0.5 0.5 0.5
""",
    )

    xs2x.main(["-i", str(inp), "-o", str(out), "--precision", "8"])
    txt = _read(out)

    # Symmetric case should map to origin.
    assert "1 1 0.00000000 0.00000000 0.00000000" in txt
