import pytest
from pathlib import Path
from proxym.projects import ProjectRegistry, Project, SourceType, ProjectStatus


@pytest.fixture
def registry(tmp_path):
    return ProjectRegistry(persist_path=tmp_path / "projects.json")


class TestProjectCRUD:
    def test_add_local(self, registry, tmp_path):
        proj_dir = tmp_path / "my-app"
        proj_dir.mkdir()
        (proj_dir / "pyproject.toml").write_text("[tool.poetry]\nname='my-app'")
        (proj_dir / ".git").mkdir()

        p = Project(name="my-app", source_type=SourceType.local,
                    source_path=str(proj_dir), local_path=str(proj_dir))
        result = registry.add(p)
        assert result.name == "my-app"
        assert result.has_git is True
        assert "python" in result.stack

    def test_find_by_name(self, registry, tmp_path):
        p = Project(name="test", source_path=str(tmp_path))
        registry.add(p)
        assert registry.find_by_name("test") is not None
        assert registry.find_by_name("nope") is None

    def test_list_filter_by_type(self, registry, tmp_path):
        registry.add(Project(name="a", source_type=SourceType.local, source_path="/a"))
        registry.add(Project(name="b", source_type=SourceType.git, source_path="git@x"))
        local = registry.list_projects(source_type=SourceType.local)
        assert len(local) == 1
        assert local[0].name == "a"

    def test_update(self, registry, tmp_path):
        p = registry.add(Project(name="upd", source_path="/tmp/upd"))
        updated = registry.update(p.id, {"description": "hello"})
        assert updated is not None
        assert updated.description == "hello"
        assert updated.last_activity is not None

    def test_update_nonexistent(self, registry):
        assert registry.update("nope", {"name": "x"}) is None

    def test_remove(self, registry, tmp_path):
        p = registry.add(Project(name="rm-me", source_path="/tmp"))
        assert registry.remove(p.id)
        assert registry.get(p.id) is None

    def test_remove_nonexistent(self, registry):
        assert registry.remove("nope") is False


class TestScan:
    def test_scan_finds_projects(self, registry, tmp_path):
        (tmp_path / "proj-a" / ".git").mkdir(parents=True)
        (tmp_path / "proj-b").mkdir()
        (tmp_path / "proj-b" / "package.json").write_text("{}")
        (tmp_path / ".hidden").mkdir()

        added = registry.scan_directory(str(tmp_path))
        names = [p.name for p in added]
        assert "proj-a" in names
        assert "proj-b" in names
        assert ".hidden" not in names

    def test_scan_skips_existing(self, registry, tmp_path):
        (tmp_path / "proj-a").mkdir()
        registry.scan_directory(str(tmp_path))
        added = registry.scan_directory(str(tmp_path))
        assert len(added) == 0  # already registered

    def test_scan_nonexistent_dir(self, registry, tmp_path):
        added = registry.scan_directory(str(tmp_path / "nope"))
        assert added == []


class TestSSHProject:
    def test_add_ssh(self, registry):
        p = registry.add_ssh_project("192.168.1.50", "/opt/api", user="deploy")
        assert p.source_type == SourceType.ssh
        assert p.ssh_host == "192.168.1.50"
        assert "deploy@192.168.1.50" in p.source_path


class TestPersistence:
    def test_save_and_reload(self, tmp_path):
        path = tmp_path / "projects.json"
        r1 = ProjectRegistry(persist_path=path)
        r1.add(Project(name="test", source_path="/tmp/test"))

        r2 = ProjectRegistry(persist_path=path)
        assert r2.find_by_name("test") is not None

    def test_empty_load(self, tmp_path):
        path = tmp_path / "projects.json"
        # No file exists — should not fail
        r = ProjectRegistry(persist_path=path)
        assert r.list_projects() == []


class TestEnrichment:
    def test_detect_python_stack(self, registry, tmp_path):
        proj = tmp_path / "pyapp"
        proj.mkdir()
        (proj / "pyproject.toml").write_text("[project]\nname='pyapp'\ndependencies=['fastapi']")
        p = Project(name="pyapp", source_path=str(proj), local_path=str(proj))
        result = registry.add(p)
        assert "python" in result.stack
        assert "fastapi" in result.frameworks

    def test_detect_js_stack(self, registry, tmp_path):
        proj = tmp_path / "jsapp"
        proj.mkdir()
        (proj / "package.json").write_text('{"dependencies": {"react": "^18"}}')
        p = Project(name="jsapp", source_path=str(proj), local_path=str(proj))
        result = registry.add(p)
        assert "javascript" in result.stack
        assert "react" in result.frameworks

    def test_detect_git(self, registry, tmp_path):
        proj = tmp_path / "gitapp"
        proj.mkdir()
        (proj / ".git").mkdir()
        p = Project(name="gitapp", source_path=str(proj), local_path=str(proj))
        result = registry.add(p)
        assert result.has_git is True
