"""
Milestone 5: Enhancement Tests

Tests for recursive listing, exists, stat, and other enhanced features.
"""


class TestRecursiveListing:
    """Tests for recursive directory listing."""

    def test_list_recursive_finds_all_files(self, auth_client, tmp_path, monkeypatch):
        """Recursive list should find files in subdirectories."""
        client, token = auth_client
        monkeypatch.setenv("FSAL_ROOT", str(tmp_path))

        # Create nested structure
        (tmp_path / "a").mkdir()
        (tmp_path / "a" / "b").mkdir()
        (tmp_path / "a" / "b" / "c").mkdir()
        (tmp_path / "file1.txt").write_text("root")
        (tmp_path / "a" / "file2.txt").write_text("level1")
        (tmp_path / "a" / "b" / "file3.txt").write_text("level2")
        (tmp_path / "a" / "b" / "c" / "file4.txt").write_text("level3")

        response = client.post(
            "/v1/fs/list",
            json={"path": ".", "recursive": True},
            headers={"Authorization": f"Bearer {token}"},
        )

        assert response.status_code == 200
        entries = response.json()
        paths = [e["path"] for e in entries]

        # Should find all files and directories
        assert "file1.txt" in paths
        assert "a/file2.txt" in paths
        assert "a/b/file3.txt" in paths
        assert "a/b/c/file4.txt" in paths

    def test_list_recursive_with_max_depth(self, auth_client, tmp_path, monkeypatch):
        """Recursive list should respect max_depth."""
        client, token = auth_client
        monkeypatch.setenv("FSAL_ROOT", str(tmp_path))

        # Create nested structure
        (tmp_path / "a" / "b" / "c").mkdir(parents=True)
        (tmp_path / "a" / "file1.txt").write_text("level1")
        (tmp_path / "a" / "b" / "file2.txt").write_text("level2")
        (tmp_path / "a" / "b" / "c" / "file3.txt").write_text("level3")

        response = client.post(
            "/v1/fs/list",
            json={"path": ".", "recursive": True, "max_depth": 1},
            headers={"Authorization": f"Bearer {token}"},
        )

        assert response.status_code == 200
        entries = response.json()
        paths = [e["path"] for e in entries]

        # Should find level 0 and 1 only
        assert "a" in paths
        assert "a/file1.txt" in paths
        # Level 2+ should NOT be included
        assert "a/b/file2.txt" not in paths
        assert "a/b/c/file3.txt" not in paths

    def test_list_recursive_with_glob_filter(self, auth_client, tmp_path, monkeypatch):
        """Recursive list should apply glob filter."""
        client, token = auth_client
        monkeypatch.setenv("FSAL_ROOT", str(tmp_path))

        # Create mixed files
        (tmp_path / "sub").mkdir()
        (tmp_path / "file.txt").write_text("txt")
        (tmp_path / "file.py").write_text("py")
        (tmp_path / "sub" / "nested.txt").write_text("nested txt")
        (tmp_path / "sub" / "nested.py").write_text("nested py")

        response = client.post(
            "/v1/fs/list",
            json={"path": ".", "recursive": True, "glob": "*.py"},
            headers={"Authorization": f"Bearer {token}"},
        )

        assert response.status_code == 200
        entries = response.json()
        paths = [e["path"] for e in entries]

        # Should only find .py files
        assert "file.py" in paths
        assert "sub/nested.py" in paths
        assert "file.txt" not in paths
        assert "sub/nested.txt" not in paths

    def test_list_recursive_with_max_entries(self, auth_client, tmp_path, monkeypatch):
        """Recursive list should respect max_entries limit."""
        client, token = auth_client
        monkeypatch.setenv("FSAL_ROOT", str(tmp_path))

        # Create many files
        for i in range(20):
            (tmp_path / f"file{i:02d}.txt").write_text(f"content {i}")

        response = client.post(
            "/v1/fs/list",
            json={"path": ".", "recursive": True, "max_entries": 5},
            headers={"Authorization": f"Bearer {token}"},
        )

        assert response.status_code == 200
        entries = response.json()
        assert len(entries) == 5


class TestExistsEndpoint:
    """Tests for the /v1/fs/exists endpoint."""

    def test_exists_returns_true_for_existing_file(self, auth_client, tmp_path, monkeypatch):
        """Exists should return true for existing files."""
        client, token = auth_client
        monkeypatch.setenv("FSAL_ROOT", str(tmp_path))

        (tmp_path / "exists.txt").write_text("hello")

        response = client.post(
            "/v1/fs/exists",
            json={"path": "exists.txt"},
            headers={"Authorization": f"Bearer {token}"},
        )

        assert response.status_code == 200
        data = response.json()
        assert data["exists"] is True
        assert data["path"] == "exists.txt"

    def test_exists_returns_false_for_missing_file(self, auth_client, tmp_path, monkeypatch):
        """Exists should return false for missing files."""
        client, token = auth_client
        monkeypatch.setenv("FSAL_ROOT", str(tmp_path))

        response = client.post(
            "/v1/fs/exists",
            json={"path": "nonexistent.txt"},
            headers={"Authorization": f"Bearer {token}"},
        )

        assert response.status_code == 200
        data = response.json()
        assert data["exists"] is False

    def test_exists_returns_true_for_directory(self, auth_client, tmp_path, monkeypatch):
        """Exists should return true for existing directories."""
        client, token = auth_client
        monkeypatch.setenv("FSAL_ROOT", str(tmp_path))

        (tmp_path / "subdir").mkdir()

        response = client.post(
            "/v1/fs/exists",
            json={"path": "subdir"},
            headers={"Authorization": f"Bearer {token}"},
        )

        assert response.status_code == 200
        assert response.json()["exists"] is True


class TestStatEndpoint:
    """Tests for the /v1/fs/stat endpoint."""

    def test_stat_returns_file_info(self, auth_client, tmp_path, monkeypatch):
        """Stat should return detailed file information."""
        client, token = auth_client
        monkeypatch.setenv("FSAL_ROOT", str(tmp_path))

        content = b"hello world"
        (tmp_path / "test.txt").write_bytes(content)

        response = client.post(
            "/v1/fs/stat",
            json={"path": "test.txt"},
            headers={"Authorization": f"Bearer {token}"},
        )

        assert response.status_code == 200
        data = response.json()
        assert data["exists"] is True
        assert data["is_file"] is True
        assert data["is_dir"] is False
        assert data["size"] == len(content)
        assert data["mtime"] is not None

    def test_stat_returns_directory_info(self, auth_client, tmp_path, monkeypatch):
        """Stat should return detailed directory information."""
        client, token = auth_client
        monkeypatch.setenv("FSAL_ROOT", str(tmp_path))

        (tmp_path / "mydir").mkdir()

        response = client.post(
            "/v1/fs/stat",
            json={"path": "mydir"},
            headers={"Authorization": f"Bearer {token}"},
        )

        assert response.status_code == 200
        data = response.json()
        assert data["exists"] is True
        assert data["is_file"] is False
        assert data["is_dir"] is True

    def test_stat_returns_exists_false_for_missing(self, auth_client, tmp_path, monkeypatch):
        """Stat should return exists=false for missing paths (no 404)."""
        client, token = auth_client
        monkeypatch.setenv("FSAL_ROOT", str(tmp_path))

        response = client.post(
            "/v1/fs/stat",
            json={"path": "missing.txt"},
            headers={"Authorization": f"Bearer {token}"},
        )

        # Should NOT be 404 - stat returns exists: false instead
        assert response.status_code == 200
        data = response.json()
        assert data["exists"] is False
        assert data["is_file"] is False
        assert data["is_dir"] is False


class TestSafeIOEnhancements:
    """Tests for the safeio module enhancements."""

    def test_listdir_recursive_basic(self, tmp_path):
        """Test basic recursive listing."""
        from aperion_fsal.core.safeio import listdir_recursive

        # Create structure
        (tmp_path / "a" / "b").mkdir(parents=True)
        (tmp_path / "file1.txt").write_text("1")
        (tmp_path / "a" / "file2.txt").write_text("2")
        (tmp_path / "a" / "b" / "file3.txt").write_text("3")

        entries = listdir_recursive(".", root=tmp_path)
        paths = [e["path"] for e in entries]

        assert "file1.txt" in paths
        assert "a" in paths
        assert "a/file2.txt" in paths
        assert "a/b" in paths
        assert "a/b/file3.txt" in paths

    def test_stat_existing_file(self, tmp_path):
        """Test stat on existing file."""
        from aperion_fsal.core.safeio import stat

        (tmp_path / "test.txt").write_text("hello")

        result = stat("test.txt", root=tmp_path)

        assert result["exists"] is True
        assert result["is_file"] is True
        assert result["is_dir"] is False
        assert result["size"] == 5

    def test_stat_missing_file(self, tmp_path):
        """Test stat on missing file returns exists=false."""
        from aperion_fsal.core.safeio import stat

        result = stat("nonexistent.txt", root=tmp_path)

        assert result["exists"] is False

    def test_exists_function(self, tmp_path):
        """Test exists function."""
        from aperion_fsal.core.safeio import exists

        (tmp_path / "real.txt").write_text("exists")

        assert exists("real.txt", root=tmp_path) is True
        assert exists("fake.txt", root=tmp_path) is False

    def test_listdir_recursive_files_only(self, tmp_path):
        """Test recursive listing with files_only filter."""
        from aperion_fsal.core.safeio import listdir_recursive

        (tmp_path / "dir1" / "dir2").mkdir(parents=True)
        (tmp_path / "file.txt").write_text("content")
        (tmp_path / "dir1" / "nested.txt").write_text("nested")

        entries = listdir_recursive(".", files_only=True, root=tmp_path)

        # Should only have files
        for entry in entries:
            assert entry["is_dir"] is False

        paths = [e["path"] for e in entries]
        assert "file.txt" in paths
        assert "dir1/nested.txt" in paths


class TestMetricsForNewEndpoints:
    """Tests verifying metrics are recorded for new endpoints."""

    def test_exists_records_operation(self, auth_client, tmp_path, monkeypatch):
        """Exists endpoint should record operation metric."""
        client, token = auth_client
        monkeypatch.setenv("FSAL_ROOT", str(tmp_path))

        # Do an exists check
        client.post(
            "/v1/fs/exists",
            json={"path": "test"},
            headers={"Authorization": f"Bearer {token}"},
        )

        # Check metrics
        metrics = client.get("/metrics").text
        assert "fsal_operations_total" in metrics

    def test_stat_records_operation(self, auth_client, tmp_path, monkeypatch):
        """Stat endpoint should record operation metric."""
        client, token = auth_client
        monkeypatch.setenv("FSAL_ROOT", str(tmp_path))

        client.post(
            "/v1/fs/stat",
            json={"path": "test"},
            headers={"Authorization": f"Bearer {token}"},
        )

        metrics = client.get("/metrics").text
        assert "fsal_operations_total" in metrics
