from __future__ import annotations

import os
import sys
from pathlib import Path

sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from vibelexity.circular_deps import find_cycles, format_json, format_text
from vibelexity.circular_deps.models import Cycle, ImportInfo
from vibelexity.circular_deps.parsers.python import PythonImportParser


def test_python_parser_extract_import():
    parser = PythonImportParser()
    source = """
from foo import bar
import os
from .. import baz
"""
    imports = parser.extract_imports(source, "test.py")
    assert len(imports) == 3
    assert imports[0].raw_module == "foo"
    assert imports[1].raw_module == "os"
    assert imports[2].import_type == "relative"


def test_cycle_detection_simple():
    """Test simple 2-file circular dependency."""
    import shutil
    import tempfile

    tmpdir = Path(tempfile.mkdtemp())
    try:
        a_py = tmpdir / "a.py"
        b_py = tmpdir / "b.py"

        a_py.write_text("from b import foo\ndef bar():\n    return 'bar'\n")
        b_py.write_text("from a import bar\ndef foo():\n    return 'foo'\n")

        files = [a_py, b_py]
        cycles = find_cycles(files)

        assert len(cycles) == 1
        assert cycles[0].depth == 2
        assert cycles[0].severity == "warning"
    finally:
        shutil.rmtree(tmpdir)


def test_format_text():
    cycle = Cycle(
        files=["a.py", "b.py", "a.py"],
        edges=[("a.py", "b.py", 3), ("b.py", "a.py", 5)],
        depth=2,
    )
    output = format_text([cycle])

    assert "Warning: cycle detected" in output
    assert "a.py:3" in output or "a.py" in output
    assert "b.py" in output


def test_format_json():
    cycles = [
        Cycle(
            files=["a.py", "b.py", "a.py"],
            edges=[("a.py", "b.py", 3), ("b.py", "a.py", 5)],
            depth=2,
        )
    ]

    output = format_json(cycles)
    assert '"severity": "warning"' in output
    assert '"depth": 2' in output
    assert '"total_cycles": 1' in output


def test_no_cycles_linear_chain():
    """Test linear import chain with no circular dependencies."""
    import shutil
    import tempfile

    tmpdir = Path(tempfile.mkdtemp())
    try:
        a_py = tmpdir / "a.py"
        b_py = tmpdir / "b.py"
        c_py = tmpdir / "c.py"

        a_py.write_text("import b\n")
        b_py.write_text("import sys\n")
        c_py.write_text("import os\n")

        files = [a_py, b_py, c_py]
        cycles = find_cycles(files)

        assert len(cycles) == 0
    finally:
        shutil.rmtree(tmpdir)


def test_transitive_cycle_three_files():
    """Test transitive cycle with 3 files."""
    import shutil
    import tempfile

    tmpdir = Path(tempfile.mkdtemp())
    try:
        a_py = tmpdir / "a.py"
        b_py = tmpdir / "b.py"
        c_py = tmpdir / "c.py"

        a_py.write_text("import b\n")
        b_py.write_text("import c\n")
        c_py.write_text("import a\n")

        files = [a_py, b_py, c_py]
        cycles = find_cycles(files)

        assert len(cycles) == 1
        assert cycles[0].depth == 3
    finally:
        shutil.rmtree(tmpdir)


def test_cycle_detection_in_src_subdirectory():
    """Test circular dependency detection with files in ./src subdirectory."""
    import shutil
    import tempfile

    tmpdir = Path(tempfile.mkdtemp())
    try:
        src_dir = tmpdir / "src"
        src_dir.mkdir(parents=True, exist_ok=True)

        afet_dir = src_dir / "afet"
        bfet_dir = src_dir / "bfet"
        afet_dir.mkdir(parents=True, exist_ok=True)
        bfet_dir.mkdir(parents=True, exist_ok=True)

        (afet_dir / "__init__.py").write_text("")
        (bfet_dir / "__init__.py").write_text("")

        a_py = afet_dir / "a.py"
        b_py = bfet_dir / "b.py"

        a_py.write_text("from bfet.b import foo\n")
        b_py.write_text("from afet.a import bar\n")

        files = [a_py, b_py]
        cycles = find_cycles(files)

        assert len(cycles) == 1
    finally:
        shutil.rmtree(tmpdir)


def test_cycle_nested_to_root():
    """Test circular dependency with nested module importing parent."""
    import shutil
    import tempfile

    tmpdir = Path(tempfile.mkdtemp())
    try:
        analysis_dir = tmpdir / "analysis"
        analysis_dir.mkdir(parents=True, exist_ok=True)
        (analysis_dir / "__init__.py").write_text("")

        verticality_py = analysis_dir / "verticality.py"
        index_py = tmpdir / "index.py"

        verticality_py.write_text("from index import foo\n")
        index_py.write_text("from analysis.verticality import bar\n")

        files = [verticality_py, index_py]
        cycles = find_cycles(files)

        assert len(cycles) == 1
        assert cycles[0].depth == 2
    finally:
        shutil.rmtree(tmpdir)
