# tests/crud/syndarix/conftest.py
"""
Shared fixtures for Syndarix CRUD tests.
"""

import uuid
from datetime import date, timedelta
from decimal import Decimal

import pytest
import pytest_asyncio

from app.models.syndarix import (
    AgentInstance,
    AgentStatus,
    AgentType,
    AutonomyLevel,
    Issue,
    IssuePriority,
    IssueStatus,
    Project,
    ProjectStatus,
    Sprint,
    SprintStatus,
)
from app.models.user import User
from app.schemas.syndarix import (
    AgentTypeCreate,
    ProjectCreate,
)


@pytest.fixture
def project_create_data():
    """Return data for creating a project via schema."""
    return ProjectCreate(
        name="Test Project",
        slug="test-project-crud",
        description="A test project for CRUD testing",
        autonomy_level=AutonomyLevel.MILESTONE,
        status=ProjectStatus.ACTIVE,
        settings={"mcp_servers": ["gitea"]},
    )


@pytest.fixture
def agent_type_create_data():
    """Return data for creating an agent type via schema."""
    return AgentTypeCreate(
        name="Backend Engineer",
        slug="backend-engineer-crud",
        description="Specialized in backend development",
        expertise=["python", "fastapi", "postgresql"],
        personality_prompt="You are an expert backend engineer with deep knowledge of Python and FastAPI.",
        primary_model="claude-opus-4-5-20251101",
        fallback_models=["claude-sonnet-4-20250514"],
        model_params={"temperature": 0.7, "max_tokens": 4096},
        mcp_servers=["gitea", "file-system"],
        tool_permissions={"allowed": ["*"], "denied": []},
        is_active=True,
    )


@pytest.fixture
def sprint_create_data():
    """Return data for creating a sprint via schema."""
    today = date.today()
    return {
        "name": "Sprint 1",
        "number": 1,
        "goal": "Complete initial setup and core features",
        "start_date": today,
        "end_date": today + timedelta(days=14),
        "status": SprintStatus.PLANNED,
        "planned_points": 21,
        "velocity": 0,
    }


@pytest.fixture
def issue_create_data():
    """Return data for creating an issue via schema."""
    return {
        "title": "Implement user authentication",
        "body": "As a user, I want to log in securely so that I can access my account.",
        "status": IssueStatus.OPEN,
        "priority": IssuePriority.HIGH,
        "labels": ["backend", "security"],
        "story_points": 5,
    }


@pytest_asyncio.fixture
async def test_owner_crud(async_test_db):
    """Create a test user to be used as project owner in CRUD tests."""
    from app.core.auth import get_password_hash

    _test_engine, AsyncTestingSessionLocal = async_test_db
    async with AsyncTestingSessionLocal() as session:
        user = User(
            id=uuid.uuid4(),
            email="crud-owner@example.com",
            password_hash=get_password_hash("TestPassword123!"),
            first_name="CRUD",
            last_name="Owner",
            is_active=True,
            is_superuser=False,
        )
        session.add(user)
        await session.commit()
        await session.refresh(user)
        return user


@pytest_asyncio.fixture
async def test_project_crud(async_test_db, test_owner_crud, project_create_data):
    """Create a test project in the database for CRUD tests."""
    _test_engine, AsyncTestingSessionLocal = async_test_db
    async with AsyncTestingSessionLocal() as session:
        project = Project(
            id=uuid.uuid4(),
            name=project_create_data.name,
            slug=project_create_data.slug,
            description=project_create_data.description,
            autonomy_level=project_create_data.autonomy_level,
            status=project_create_data.status,
            settings=project_create_data.settings,
            owner_id=test_owner_crud.id,
        )
        session.add(project)
        await session.commit()
        await session.refresh(project)
        return project


@pytest_asyncio.fixture
async def test_agent_type_crud(async_test_db, agent_type_create_data):
    """Create a test agent type in the database for CRUD tests."""
    _test_engine, AsyncTestingSessionLocal = async_test_db
    async with AsyncTestingSessionLocal() as session:
        agent_type = AgentType(
            id=uuid.uuid4(),
            name=agent_type_create_data.name,
            slug=agent_type_create_data.slug,
            description=agent_type_create_data.description,
            expertise=agent_type_create_data.expertise,
            personality_prompt=agent_type_create_data.personality_prompt,
            primary_model=agent_type_create_data.primary_model,
            fallback_models=agent_type_create_data.fallback_models,
            model_params=agent_type_create_data.model_params,
            mcp_servers=agent_type_create_data.mcp_servers,
            tool_permissions=agent_type_create_data.tool_permissions,
            is_active=agent_type_create_data.is_active,
        )
        session.add(agent_type)
        await session.commit()
        await session.refresh(agent_type)
        return agent_type


@pytest_asyncio.fixture
async def test_agent_instance_crud(async_test_db, test_project_crud, test_agent_type_crud):
    """Create a test agent instance in the database for CRUD tests."""
    _test_engine, AsyncTestingSessionLocal = async_test_db
    async with AsyncTestingSessionLocal() as session:
        agent_instance = AgentInstance(
            id=uuid.uuid4(),
            agent_type_id=test_agent_type_crud.id,
            project_id=test_project_crud.id,
            name="TestAgent",
            status=AgentStatus.IDLE,
            current_task=None,
            short_term_memory={},
            long_term_memory_ref=None,
            session_id=None,
            tasks_completed=0,
            tokens_used=0,
            cost_incurred=Decimal("0.0000"),
        )
        session.add(agent_instance)
        await session.commit()
        await session.refresh(agent_instance)
        return agent_instance


@pytest_asyncio.fixture
async def test_sprint_crud(async_test_db, test_project_crud, sprint_create_data):
    """Create a test sprint in the database for CRUD tests."""
    _test_engine, AsyncTestingSessionLocal = async_test_db
    async with AsyncTestingSessionLocal() as session:
        sprint = Sprint(
            id=uuid.uuid4(),
            project_id=test_project_crud.id,
            **sprint_create_data,
        )
        session.add(sprint)
        await session.commit()
        await session.refresh(sprint)
        return sprint


@pytest_asyncio.fixture
async def test_issue_crud(async_test_db, test_project_crud, issue_create_data):
    """Create a test issue in the database for CRUD tests."""
    _test_engine, AsyncTestingSessionLocal = async_test_db
    async with AsyncTestingSessionLocal() as session:
        issue = Issue(
            id=uuid.uuid4(),
            project_id=test_project_crud.id,
            **issue_create_data,
        )
        session.add(issue)
        await session.commit()
        await session.refresh(issue)
        return issue
