import os
import shutil
import uuid

from fastapi import APIRouter, Depends, HTTPException, Response, status
from sqlalchemy import func, select
from sqlalchemy.ext.asyncio import AsyncSession

from src.auth.dependencies import (
    _get_owned_project,
    _get_user,
    get_current_user_id,
    get_db_session,
)
from src.models import GitRepository
from src.models.project import Project
from src.models import SSHKey
from src.models import ToolInstance
from src.schemas.project import (
    ProjectCreate,
    ProjectResponse,
    ProjectUpdate,
    SetDefaultSSHKeyRequest,
)

router = APIRouter(prefix="/projects", tags=["projects"])


@router.post(
    "",
    response_model=ProjectResponse,
    status_code=status.HTTP_201_CREATED,
    summary="Create a new project",
    description="Create a new project for the authenticated user.",
)
async def create_project(
    data: ProjectCreate,
    user_id: uuid.UUID = Depends(get_current_user_id),
    session: AsyncSession = Depends(get_db_session),
) -> Project:
    """Create a new project.

    Args:
        data: Project creation data including name and optional description.
        user_id: ID of the authenticated user.
        session: Database session.

    Returns:
        The newly created project.
    """
    user = await _get_user(session, user_id)
    project = Project(
        name=data.name,
        description=data.description,
        owner_id=user.id,
        default_ssh_key_id=None,
    )
    session.add(project)
    await session.commit()
    await session.refresh(project)
    return project


@router.get(
    "",
    summary="List all projects",
    description="Retrieve all projects owned by the authenticated user with repositories and workspaces.",
)
async def list_projects(
    user_id: uuid.UUID = Depends(get_current_user_id),
    session: AsyncSession = Depends(get_db_session),
) -> list[dict]:
    """List all projects for the authenticated user.

    Returns projects with nested repositories and workspaces for inline display.
    """
    user = await _get_user(session, user_id)
    result = await session.execute(
        select(Project)
        .where(Project.owner_id == user.id)
        .order_by(Project.created_at.desc())
    )
    projects = result.scalars().all()

    from src.models import Workspace

    enriched = []
    for project in projects:
        repos_result = await session.execute(
            select(GitRepository).where(GitRepository.project_id == project.id)
        )
        repositories = []
        for repo in repos_result.scalars().all():
            ws_result = await session.execute(
                select(Workspace).where(Workspace.repo_id == repo.id)
            )
            workspaces = []
            for ws in ws_result.scalars().all():
                # Count instances
                inst_result = await session.execute(
                    select(func.count()).where(ToolInstance.workspace_id == ws.id)
                )
                instance_count = inst_result.scalar() or 0
                workspaces.append(
                    {
                        "id": str(ws.id),
                        "name": ws.name,
                        "branch": ws.branch,
                        "status": ws.status,
                        "instance_count": instance_count,
                    }
                )

            repositories.append(
                {
                    "id": str(repo.id),
                    "name": repo.name,
                    "remote_url": repo.remote_url,
                    "workspaces": workspaces,
                }
            )

        enriched.append(
            {
                "id": str(project.id),
                "name": project.name,
                "description": project.description,
                "owner_id": str(project.owner_id),
                "repositories": repositories,
                "created_at": project.created_at.isoformat()
                if project.created_at
                else None,
            }
        )

    return enriched


@router.get(
    "/{project_id}",
    response_model=ProjectResponse,
    summary="Get a project",
    description="Retrieve a specific project by ID.",
)
async def get_project(
    project_id: uuid.UUID,
    user_id: uuid.UUID = Depends(get_current_user_id),
    session: AsyncSession = Depends(get_db_session),
) -> Project:
    """Get a specific project by ID.

    Args:
        project_id: UUID of the project to retrieve.
        user_id: ID of the authenticated user.
        session: Database session.

    Returns:
        The requested project.
    """
    await _get_user(session, user_id)
    return await _get_owned_project(project_id, user_id, session)


@router.patch(
    "/{project_id}",
    response_model=ProjectResponse,
    summary="Update a project",
    description="Update a project's name or description.",
)
async def update_project(
    project_id: uuid.UUID,
    data: ProjectUpdate,
    user_id: uuid.UUID = Depends(get_current_user_id),
    session: AsyncSession = Depends(get_db_session),
) -> Project:
    """Update a project.

    Args:
        project_id: UUID of the project to update.
        data: Project update data with optional name and description.
        user_id: ID of the authenticated user.
        session: Database session.

    Returns:
        The updated project.
    """
    await _get_user(session, user_id)
    project = await _get_owned_project(project_id, user_id, session)

    if data.name is not None:
        project.name = data.name
    if data.description is not None:
        project.description = data.description

    await session.commit()
    await session.refresh(project)
    return project


@router.delete(
    "/{project_id}",
    status_code=status.HTTP_204_NO_CONTENT,
    summary="Delete a project",
    description="Delete a project and all its associated repositories.",
)
async def delete_project(
    project_id: uuid.UUID,
    user_id: uuid.UUID = Depends(get_current_user_id),
    session: AsyncSession = Depends(get_db_session),
) -> Response:
    """Delete a project and all its repositories.

    Args:
        project_id: UUID of the project to delete.
        user_id: ID of the authenticated user.
        session: Database session.

    Returns:
        Empty response with 204 status code.
    """
    await _get_user(session, user_id)
    project = await _get_owned_project(project_id, user_id, session)

    # Delete repositories from disk and database
    result = await session.execute(
        select(GitRepository).where(GitRepository.project_id == project_id)
    )
    repositories = result.scalars().all()
    for repo in repositories:
        if os.path.exists(repo.path):
            shutil.rmtree(repo.path)
        await session.delete(repo)

    await session.delete(project)
    await session.commit()
    return Response(status_code=status.HTTP_204_NO_CONTENT)


@router.patch(
    "/{project_id}/default-ssh-key",
    response_model=ProjectResponse,
    summary="Set default SSH key",
    description="Set the default SSH key for a project.",
)
async def set_default_ssh_key(
    project_id: uuid.UUID,
    data: SetDefaultSSHKeyRequest,
    user_id: uuid.UUID = Depends(get_current_user_id),
    session: AsyncSession = Depends(get_db_session),
) -> Project:
    """Set the default SSH key for a project.

    Args:
        project_id: UUID of the project.
        data: Request containing the SSH key ID to set as default.
        user_id: ID of the authenticated user.
        session: Database session.

    Returns:
        The updated project.
    """
    user = await _get_user(session, user_id)
    project = await _get_owned_project(project_id, user_id, session)

    ssh_key = await session.get(SSHKey, data.ssh_key_id)
    if ssh_key is None or ssh_key.user_id != user.id:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="invalid ssh key",
        )

    project.default_ssh_key_id = data.ssh_key_id
    await session.commit()
    await session.refresh(project)
    return project
