"""Integration tests for workspace file endpoints."""

import asyncio
import os
import tempfile
import uuid
from unittest.mock import patch

import pytest
from fastapi.testclient import TestClient
from sqlalchemy.ext.asyncio import AsyncSession

from src.models import GitRepository, Project, Workspace
from src.services.shared.workspace_manager import WorkspaceManager


def _get_user_id(client: TestClient) -> uuid.UUID:
    from src.auth.session import decode_session_cookie
    from src.config import Settings

    settings = Settings()
    cookie = client.cookies.get("session")
    data = decode_session_cookie(settings=settings, cookie_value=cookie)
    if not data:
        raise RuntimeError("No session")
    return uuid.UUID(data["user_id"])


@pytest.fixture
def test_repo_with_workspace(
    db_session: AsyncSession, authenticated_client: TestClient
):
    """Create a project, repo, and workspace backed by a temp directory."""
    user_id = _get_user_id(authenticated_client)

    async def _create():
        project = Project(name="File Test Project", owner_id=user_id)
        db_session.add(project)
        await db_session.flush()

        repo = GitRepository(
            name="file-test-repo",
            path="/tmp/file-test-repo",
            remote_url="https://example.com/repo.git",
            project_id=project.id,
            owner_id=user_id,
        )
        db_session.add(repo)
        await db_session.flush()

        tmpdir = tempfile.mkdtemp()
        ws = Workspace(
            name="dev",
            repo_id=repo.id,
            user_id=user_id,
            branch="main",
            path=tmpdir,
        )
        db_session.add(ws)
        await db_session.commit()
        await db_session.refresh(ws)
        return ws

    return asyncio.run(_create())


class TestListWorkspaceFiles:
    """Tests for GET /workspaces/{id}/files."""

    def test_list_files(
        self, authenticated_client: TestClient, test_repo_with_workspace: Workspace
    ):
        ws = test_repo_with_workspace
        os.makedirs(os.path.join(ws.path, "src"))
        with open(os.path.join(ws.path, "README.md"), "w") as f:
            f.write("# Test")

        response = authenticated_client.get(f"/workspaces/{ws.id}/files")
        assert response.status_code == 200
        data = response.json()
        names = {e["name"] for e in data["entries"]}
        assert "src" in names
        assert "README.md" in names

    def test_list_files_path_escapes_workspace(
        self, authenticated_client: TestClient, test_repo_with_workspace: Workspace
    ):
        response = authenticated_client.get(
            f"/workspaces/{test_repo_with_workspace.id}/files", params={"path": "../outside"}
        )
        assert response.status_code == 400


class TestGetFileContent:
    """Tests for GET /workspaces/{id}/files/content."""

    def test_get_content(
        self, authenticated_client: TestClient, test_repo_with_workspace: Workspace
    ):
        with open(os.path.join(test_repo_with_workspace.path, "hello.py"), "w") as f:
            f.write("print('hello')")

        response = authenticated_client.get(
            f"/workspaces/{test_repo_with_workspace.id}/files/content",
            params={"path": "hello.py"},
        )
        assert response.status_code == 200
        assert response.json()["content"] == "print('hello')"

    def test_get_missing_file(
        self, authenticated_client: TestClient, test_repo_with_workspace: Workspace
    ):
        response = authenticated_client.get(
            f"/workspaces/{test_repo_with_workspace.id}/files/content",
            params={"path": "missing.txt"},
        )
        assert response.status_code == 404


class TestWriteFileContent:
    """Tests for POST /workspaces/{id}/files/content."""

    def test_write_file(
        self, authenticated_client: TestClient, test_repo_with_workspace: Workspace
    ):
        response = authenticated_client.post(
            f"/workspaces/{test_repo_with_workspace.id}/files/content",
            json={"path": "nested/file.txt", "content": "content"},
        )
        assert response.status_code == 200
        assert os.path.exists(
            os.path.join(test_repo_with_workspace.path, "nested", "file.txt")
        )

    def test_write_file_missing_path(
        self, authenticated_client: TestClient, test_repo_with_workspace: Workspace
    ):
        response = authenticated_client.post(
            f"/workspaces/{test_repo_with_workspace.id}/files/content",
            json={"content": "content"},
        )
        assert response.status_code == 400
