import uuid
import pytest
from fastapi.testclient import TestClient


@pytest.mark.integration
class TestConfigProfilesAPI:
    """Integration tests for config profiles API."""

    def test_list_config_profiles_requires_authentication(self, test_client: TestClient) -> None:
        """Test that listing config profiles requires authentication."""
        response = test_client.get("/config-profiles")
        assert response.status_code == 401

    def test_list_config_profiles_returns_user_profiles(self, authenticated_client: TestClient) -> None:
        """Test that authenticated users can list their profiles."""
        response = authenticated_client.get("/config-profiles")
        assert response.status_code == 200
        data = response.json()
        assert isinstance(data, list)

    def test_create_config_profile_successfully(self, authenticated_client: TestClient) -> None:
        """Test creating a config profile."""
        response = authenticated_client.post(
            "/config-profiles",
            json={
                "name": "test-profile",
                "description": "Test profile",
                "env_vars": {"VAR": "value"},
                "runtime_hints": {"start_command": "npm start"},
                "mounts": [{"target": "/app", "mode": "rw", "files": {}}],
                "files": {"test.txt": "hello"},
            },
        )
        assert response.status_code == 201
        data = response.json()
        assert data["name"] == "test-profile"
        assert data["env_vars"] == {"VAR": "value"}
        assert data["files"] == {"test.txt": "hello"}
        assert data["mounts"][0]["target"] == "/app"

    def test_create_config_profile_duplicate_name(self, authenticated_client: TestClient) -> None:
        """Test that duplicate profile names are rejected."""
        # Create first profile
        response = authenticated_client.post(
            "/config-profiles",
            json={
                "name": "duplicate-profile",
                "env_vars": {},
                "files": {},
            },
        )
        assert response.status_code == 201

        # Try to create second with same name
        response = authenticated_client.post(
            "/config-profiles",
            json={
                "name": "duplicate-profile",
                "env_vars": {},
                "files": {},
            },
        )
        assert response.status_code == 409

    def test_create_config_profile_exceeds_size_limit(self, authenticated_client: TestClient) -> None:
        """Test that profiles exceeding 10MB are rejected."""
        large_content = "x" * (11 * 1024 * 1024)  # 11MB
        response = authenticated_client.post(
            "/config-profiles",
            json={
                "name": "large-profile",
                "env_vars": {},
                "files": {"large.txt": large_content},
            },
        )
        assert response.status_code == 413

    def test_create_config_profile_invalid_file_path(self, authenticated_client: TestClient) -> None:
        """Test that invalid file paths are rejected."""
        response = authenticated_client.post(
            "/config-profiles",
            json={
                "name": "bad-profile",
                "env_vars": {},
                "files": {"../../../etc/passwd": "malicious"},
            },
        )
        assert response.status_code == 422

    def test_create_config_profile_invalid_mount_target(self, authenticated_client: TestClient) -> None:
        """Test that invalid mount targets are rejected."""
        response = authenticated_client.post(
            "/config-profiles",
            json={
                "name": "bad-mount-profile",
                "env_vars": {},
                "files": {},
                "mounts": [{"target": "relative/path", "mode": "rw", "files": {}}],
            },
        )
        assert response.status_code == 422

    def test_get_config_profile_by_id(self, authenticated_client: TestClient) -> None:
        """Test getting a config profile by ID."""
        # Create profile first
        create_response = authenticated_client.post(
            "/config-profiles",
            json={
                "name": "get-test",
                "env_vars": {},
                "files": {},
            },
        )
        profile_id = create_response.json()["id"]

        # Get it back
        response = authenticated_client.get(f"/config-profiles/{profile_id}")
        assert response.status_code == 200
        data = response.json()
        assert data["name"] == "get-test"

    def test_get_config_profile_not_found(self, authenticated_client: TestClient) -> None:
        """Test getting a non-existent profile."""
        response = authenticated_client.get(f"/config-profiles/{uuid.uuid4()}")
        assert response.status_code == 404

    def test_update_config_profile_successfully(self, authenticated_client: TestClient) -> None:
        """Test updating a config profile."""
        # Create profile first
        create_response = authenticated_client.post(
            "/config-profiles",
            json={
                "name": "update-test",
                "env_vars": {},
                "files": {},
            },
        )
        profile_id = create_response.json()["id"]

        # Update it
        response = authenticated_client.put(
            f"/config-profiles/{profile_id}",
            json={
                "name": "updated-name",
                "env_vars": {"NEW_VAR": "new_value"},
            },
        )
        assert response.status_code == 200
        data = response.json()
        assert data["name"] == "updated-name"
        assert data["env_vars"] == {"NEW_VAR": "new_value"}

    def test_delete_config_profile_successfully(self, authenticated_client: TestClient) -> None:
        """Test deleting a config profile."""
        # Create profile first
        create_response = authenticated_client.post(
            "/config-profiles",
            json={
                "name": "delete-test",
                "env_vars": {},
                "files": {},
            },
        )
        profile_id = create_response.json()["id"]

        # Delete it
        response = authenticated_client.delete(f"/config-profiles/{profile_id}")
        assert response.status_code == 204

        # Verify it's gone
        get_response = authenticated_client.get(f"/config-profiles/{profile_id}")
        assert get_response.status_code == 404

    def test_update_profile_includes_successfully(self, authenticated_client: TestClient) -> None:
        """Test updating profile includes."""
        # Create base profile
        base_response = authenticated_client.post(
            "/config-profiles",
            json={
                "name": "base-profile",
                "env_vars": {"BASE_VAR": "base_value"},
                "files": {},
            },
        )
        base_id = base_response.json()["id"]

        # Create child profile
        child_response = authenticated_client.post(
            "/config-profiles",
            json={
                "name": "child-profile",
                "env_vars": {},
                "files": {},
            },
        )
        child_id = child_response.json()["id"]

        # Update includes
        response = authenticated_client.put(
            f"/config-profiles/{child_id}/includes",
            json={"includes": [base_id]},
        )
        assert response.status_code == 200
        data = response.json()
        print(f"Response data: {data}")
        print(f"Includes: {data.get('includes', 'NO INCLUDES KEY')}")
        assert len(data["includes"]) == 1, f"Expected 1 include, got {len(data.get('includes', []))}: {data.get('includes', [])}"
        assert data["includes"][0]["included_profile_id"] == base_id

    def test_update_profile_includes_cycle_detection(self, authenticated_client: TestClient) -> None:
        """Test that include cycles are detected."""
        # Create profile A
        a_response = authenticated_client.post(
            "/config-profiles",
            json={
                "name": "profile-a",
                "env_vars": {},
                "files": {},
            },
        )
        a_id = a_response.json()["id"]

        # Create profile B
        b_response = authenticated_client.post(
            "/config-profiles",
            json={
                "name": "profile-b",
                "env_vars": {},
                "files": {},
            },
        )
        b_id = b_response.json()["id"]

        # Make B include A
        authenticated_client.put(
            f"/config-profiles/{b_id}/includes",
            json={"includes": [a_id]},
        )

        # Try to make A include B (would create cycle)
        response = authenticated_client.put(
            f"/config-profiles/{a_id}/includes",
            json={"includes": [b_id]},
        )
        assert response.status_code == 400

    def test_preview_config_profile_successfully(self, authenticated_client: TestClient) -> None:
        """Test previewing a resolved config profile."""
        # Create base profile
        base_response = authenticated_client.post(
            "/config-profiles",
            json={
                "name": "preview-base",
                "env_vars": {"BASE_VAR": "base"},
                "files": {},
            },
        )
        base_id = base_response.json()["id"]

        # Create child profile
        child_response = authenticated_client.post(
            "/config-profiles",
            json={
                "name": "preview-child",
                "env_vars": {"CHILD_VAR": "child"},
                "files": {},
            },
        )
        child_id = child_response.json()["id"]

        # Make child include base
        authenticated_client.put(
            f"/config-profiles/{child_id}/includes",
            json={"includes": [base_id]},
        )

        # Preview child
        response = authenticated_client.get(f"/config-profiles/{child_id}/preview")
        assert response.status_code == 200
        data = response.json()
        assert data["profile_name"] == "preview-child"
        assert data["env_vars"]["BASE_VAR"] == "base"
        assert data["env_vars"]["CHILD_VAR"] == "child"
        assert len(data["included_profiles"]) == 1

    def test_resolve_default_profile(self, authenticated_client: TestClient) -> None:
        """Test resolving default profile for project/tool."""
        # Create a global default profile (no project/tool scoping)
        authenticated_client.post(
            "/config-profiles",
            json={
                "name": "default-profile",
                "env_vars": {},
                "files": {},
                "is_default": True,
            },
        )

        # Resolve default with random project/tool (should fall back to global)
        project_id = str(uuid.uuid4())
        tool_type_id = str(uuid.uuid4())
        response = authenticated_client.get(
            "/config-profiles/defaults/resolve",
            params={"project_id": project_id, "tool_type_id": tool_type_id},
        )
        assert response.status_code == 200
        data = response.json()
        assert data["profile_name"] == "default-profile"

    def test_resolve_default_profile_no_match(self, authenticated_client: TestClient) -> None:
        """Test resolving default profile when no profiles exist."""
        project_id = str(uuid.uuid4())
        tool_type_id = str(uuid.uuid4())

        response = authenticated_client.get(
            "/config-profiles/defaults/resolve",
            params={"project_id": project_id, "tool_type_id": tool_type_id},
        )
        assert response.status_code == 200
        data = response.json()
        assert data["profile_id"] is None

    def test_create_config_profile_with_git_mounts(self, authenticated_client: TestClient, test_project_and_repo) -> None:
        """Test creating a config profile with git mounts."""
        _project_id, repo_id = test_project_and_repo

        response = authenticated_client.post(
            "/config-profiles",
            json={
                "name": "git-mount-profile",
                "env_vars": {},
                "files": {},
                "git_mounts": [
                    {
                        "remote_url": "https://github.com/user/repo.git",
                        "source_path": ".",
                        "target_path": "/app",
                        "branch": "main",
                    }
                ],
            },
        )
        assert response.status_code == 201
        data = response.json()
        assert data["name"] == "git-mount-profile"
        assert len(data["git_mounts"]) == 1
        assert data["git_mounts"][0]["target_path"] == "/app"
        assert data["git_mounts"][0]["branch"] == "main"

    def test_update_config_profile_git_mounts(self, authenticated_client: TestClient, test_project_and_repo) -> None:
        """Test updating git mounts on a config profile."""
        _project_id, repo_id = test_project_and_repo

        # Create profile first
        create_response = authenticated_client.post(
            "/config-profiles",
            json={
                "name": "update-git-mounts",
                "env_vars": {},
                "files": {},
            },
        )
        profile_id = create_response.json()["id"]

        # Update with git mounts
        response = authenticated_client.put(
            f"/config-profiles/{profile_id}",
            json={
                "git_mounts": [
                    {
                        "remote_url": "https://github.com/user/repo.git",
                        "source_path": "config",
                        "target_path": "/config",
                    }
                ],
            },
        )
        assert response.status_code == 200
        data = response.json()
        assert len(data["git_mounts"]) == 1
        assert data["git_mounts"][0]["source_path"] == "config"

    def test_create_config_profile_invalid_git_mount_source_path(self, authenticated_client: TestClient, test_project_and_repo) -> None:
        """Test that invalid git mount source paths are rejected."""
        _project_id, repo_id = test_project_and_repo

        response = authenticated_client.post(
            "/config-profiles",
            json={
                "name": "bad-git-mount",
                "env_vars": {},
                "files": {},
                "git_mounts": [
                    {
                        "remote_url": "https://github.com/user/repo.git",
                        "source_path": "/absolute/path",
                        "target_path": "/app",
                    }
                ],
            },
        )
        assert response.status_code == 422

    def test_create_config_profile_invalid_git_mount_target_path_traversal(self, authenticated_client: TestClient, test_project_and_repo) -> None:
        """Test that git mount target paths with traversal are rejected."""
        _project_id, repo_id = test_project_and_repo

        response = authenticated_client.post(
            "/config-profiles",
            json={
                "name": "bad-git-mount-target",
                "env_vars": {},
                "files": {},
                "git_mounts": [
                    {
                        "remote_url": "https://github.com/user/repo.git",
                        "source_path": ".",
                        "target_path": "../../../etc/passwd",
                    }
                ],
            },
        )
        assert response.status_code == 422

    def test_preview_config_profile_with_git_mounts(self, authenticated_client: TestClient, test_project_and_repo) -> None:
        """Test previewing a profile with git mounts."""
        _project_id, repo_id = test_project_and_repo

        # Create profile with git mounts
        create_response = authenticated_client.post(
            "/config-profiles",
            json={
                "name": "preview-git-mounts",
                "env_vars": {},
                "files": {},
                "git_mounts": [
                    {
                        "remote_url": "https://github.com/user/repo.git",
                        "source_path": ".",
                        "target_path": "/app",
                    }
                ],
            },
        )
        profile_id = create_response.json()["id"]

        # Preview
        response = authenticated_client.get(f"/config-profiles/{profile_id}/preview")
        assert response.status_code == 200
        data = response.json()
        assert len(data["git_mounts"]) == 1
        assert data["git_mounts"][0]["remote_url"] == "https://github.com/user/repo.git"
