"""Unit tests for GMT read/write/container operations."""
import tempfile
from pathlib import Path

import pytest

from activepathways import GMT, Pathway, is_gmt, make_background, read_gmt, write_gmt


# ---------------------------------------------------------------------------
# Construction and container API
# ---------------------------------------------------------------------------

def test_gmt_empty():
    g = GMT()
    assert len(g) == 0
    assert list(g) == []


def test_gmt_from_pathways():
    p1 = Pathway(id="A", name="Alpha", genes=["G1", "G2"])
    p2 = Pathway(id="B", name="Beta", genes=["G3"])
    g = GMT([p1, p2])
    assert len(g) == 2


def test_gmt_duplicate_ids_raise():
    p1 = Pathway(id="X", name="X1", genes=[])
    p2 = Pathway(id="X", name="X2", genes=[])
    with pytest.raises(ValueError, match="unique"):
        GMT([p1, p2])


def test_gmt_getitem_str():
    p = Pathway(id="REAC:1", name="Pathway 1", genes=["G1"])
    g = GMT([p])
    assert g["REAC:1"].name == "Pathway 1"


def test_gmt_getitem_int():
    p1 = Pathway(id="A", name="Alpha", genes=[])
    p2 = Pathway(id="B", name="Beta", genes=[])
    g = GMT([p1, p2])
    assert g[0].id == "A"
    assert g[1].id == "B"


def test_gmt_getitem_slice():
    pathways = [Pathway(id=str(i), name=f"P{i}", genes=[]) for i in range(5)]
    g = GMT(pathways)
    sub = g[1:3]
    assert isinstance(sub, GMT)
    assert len(sub) == 2
    assert sub[0].id == "1"


def test_gmt_getitem_list_of_ids():
    p1 = Pathway(id="A", name="Alpha", genes=[])
    p2 = Pathway(id="B", name="Beta", genes=[])
    p3 = Pathway(id="C", name="Gamma", genes=[])
    g = GMT([p1, p2, p3])
    sub = g[["A", "C"]]
    assert isinstance(sub, GMT)
    assert [t.id for t in sub] == ["A", "C"]


def test_gmt_contains():
    g = GMT([Pathway(id="X", name="X", genes=[])])
    assert "X" in g
    assert "Y" not in g


def test_gmt_ids_and_names():
    p1 = Pathway(id="A", name="Alpha", genes=[])
    p2 = Pathway(id="B", name="Beta", genes=[])
    g = GMT([p1, p2])
    assert g.ids() == ["A", "B"]
    assert g.names() == ["Alpha", "Beta"]


def test_gmt_repr():
    g = GMT([Pathway(id="A", name="Alpha", genes=["G1"])])
    assert "1 terms" in repr(g)


def test_is_gmt_true_and_false():
    assert is_gmt(GMT()) is True
    assert is_gmt("not a gmt") is False
    assert is_gmt(None) is False


# ---------------------------------------------------------------------------
# read_gmt / write_gmt round-trip
# ---------------------------------------------------------------------------

def test_read_gmt(gmt_file):
    g = read_gmt(gmt_file)
    assert isinstance(g, GMT)
    assert len(g) > 0
    for term in g:
        assert term.id
        assert term.name
        assert len(term.genes) > 0


def test_read_gmt_preserves_gene_order(gmt_file):
    g = read_gmt(gmt_file)
    first = g[0]
    assert first.genes == list(dict.fromkeys(first.genes))  # no implicit de-dup by read_gmt


def test_write_read_roundtrip():
    original = GMT([
        Pathway(id="P1", name="Pathway One", genes=["GENE_A", "GENE_B", "GENE_C"]),
        Pathway(id="P2", name="Pathway Two", genes=["GENE_D"]),
    ])
    with tempfile.NamedTemporaryFile(suffix=".gmt", mode="w", delete=False) as f:
        fname = f.name
    write_gmt(original, fname)
    reloaded = read_gmt(fname)
    assert len(reloaded) == len(original)
    for orig, rel in zip(original, reloaded):
        assert orig.id == rel.id
        assert orig.name == rel.name
        assert orig.genes == rel.genes
    Path(fname).unlink()


def test_write_gmt_rejects_non_gmt():
    with pytest.raises(TypeError):
        write_gmt({"not": "a gmt"}, "/tmp/out.gmt")


def test_read_gmt_malformed_raises(tmp_path):
    bad = tmp_path / "bad.gmt"
    bad.write_text("only_one_field\n")
    with pytest.raises(ValueError, match="Malformed"):
        read_gmt(str(bad))


def test_read_gmt_skips_blank_lines(tmp_path):
    f = tmp_path / "blanks.gmt"
    f.write_text("P1\tPathway 1\tG1\tG2\n\nP2\tPathway 2\tG3\n")
    g = read_gmt(str(f))
    assert len(g) == 2


# ---------------------------------------------------------------------------
# make_background
# ---------------------------------------------------------------------------

def test_make_background_returns_unique_genes(gmt):
    bg = make_background(gmt)
    assert len(bg) == len(set(bg))  # no duplicates


def test_make_background_covers_all_genes(gmt):
    bg = set(make_background(gmt))
    for term in gmt:
        assert all(g in bg for g in term.genes)


def test_make_background_rejects_non_gmt():
    with pytest.raises(TypeError):
        make_background(["gene1", "gene2"])
