"""Config profile API endpoints."""

import logging
import uuid

from fastapi import APIRouter, Depends, HTTPException, Query, status
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import selectinload

from src.auth.dependencies import get_current_user_id, get_db_session
from src.models import ConfigProfile, ConfigProfileInclude, UserConfig
from src.schemas.config import (
    ConfigProfileCreate,
    ConfigProfileIncludeUpdate,
    ConfigProfileResponse,
    ConfigProfileUpdate,
    DefaultProfilesUpdate,
    ValidateGitUrlRequest,
    ValidateGitUrlResponse,
)
from src.services.config.config_profile_resolver import (
    ConfigProfileCycleError,
    resolve_profile,
    resolved_profile_to_dict,
)
from src.services.config.crud_service import (
    create_profile,
    get_or_create_user_config,
    get_profile_with_includes,
    profile_to_response,
    update_includes,
    update_profile,
    validate_default_profiles,
)
from src.services.config.resolver_service import (
    resolve_default_profile,
    validate_git_url,
)

logger = logging.getLogger(__name__)

router = APIRouter(prefix="/config-profiles", tags=["config-profiles"])


@router.get("", response_model=list[ConfigProfileResponse])
async def list_config_profiles(
    project_id: str | None = Query(None, description="Filter by project compatibility"),
    tool_type_id: str | None = Query(
        None, description="Filter by tool type compatibility"
    ),
    current_user_id: uuid.UUID = Depends(get_current_user_id),
    session: AsyncSession = Depends(get_db_session),
):
    """List config profiles, optionally filtered by compatibility."""
    user_uuid = current_user_id
    query = (
        select(ConfigProfile)
        .where(ConfigProfile.user_id == user_uuid)
        .options(selectinload(ConfigProfile.includes))
    )

    if project_id or tool_type_id:
        from sqlalchemy import or_

        project_uuid = uuid.UUID(project_id) if project_id else None
        tool_uuid = uuid.UUID(tool_type_id) if tool_type_id else None

        conditions: list = []
        conditions.append(
            (ConfigProfile.project_id.is_(None))
            & (ConfigProfile.tool_type_id.is_(None))
        )
        if project_uuid:
            conditions.append(ConfigProfile.project_id == project_uuid)
        if tool_uuid:
            conditions.append(ConfigProfile.tool_type_id == tool_uuid)
        if project_uuid and tool_uuid:
            conditions.append(
                (ConfigProfile.project_id == project_uuid)
                & (ConfigProfile.tool_type_id == tool_uuid)
            )

        query = query.where(or_(*conditions))

    result = await session.execute(query)
    profiles = result.scalars().all()
    return [profile_to_response(p) for p in profiles]


@router.post(
    "", response_model=ConfigProfileResponse, status_code=status.HTTP_201_CREATED
)
async def create_config_profile(
    data: ConfigProfileCreate,
    current_user_id: uuid.UUID = Depends(get_current_user_id),
    session: AsyncSession = Depends(get_db_session),
):
    """Create a new config profile."""
    profile = await create_profile(session, current_user_id, data)
    logger.debug("Created config profile %s for user %s", profile.id, current_user_id)
    return profile_to_response(profile)


@router.get("/{profile_id}", response_model=ConfigProfileResponse)
async def get_config_profile(
    profile_id: str,
    current_user_id: uuid.UUID = Depends(get_current_user_id),
    session: AsyncSession = Depends(get_db_session),
):
    """Get a config profile by ID."""
    profile = await get_profile_with_includes(session, uuid.UUID(profile_id))
    if profile is None:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND, detail="Profile not found"
        )
    if profile.user_id != current_user_id:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN, detail="Not authorized"
        )
    return profile_to_response(profile)


@router.put("/{profile_id}", response_model=ConfigProfileResponse)
async def update_config_profile(
    profile_id: str,
    data: ConfigProfileUpdate,
    current_user_id: uuid.UUID = Depends(get_current_user_id),
    session: AsyncSession = Depends(get_db_session),
):
    """Update a config profile."""
    profile = await get_profile_with_includes(session, uuid.UUID(profile_id))
    if profile is None:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND, detail="Profile not found"
        )
    if profile.user_id != current_user_id:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN, detail="Not authorized"
        )

    profile = await update_profile(session, profile, data)
    logger.debug("Updated config profile %s", profile.id)
    return profile_to_response(profile)


@router.delete("/{profile_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_config_profile(
    profile_id: str,
    current_user_id: uuid.UUID = Depends(get_current_user_id),
    session: AsyncSession = Depends(get_db_session),
):
    """Delete a config profile."""
    profile = await get_profile_with_includes(session, uuid.UUID(profile_id))
    if profile is None:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND, detail="Profile not found"
        )
    if profile.user_id != current_user_id:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN, detail="Not authorized"
        )

    await session.delete(profile)
    await session.commit()

    logger.debug("Deleted config profile %s", profile_id)
    return None


@router.put("/{profile_id}/includes", response_model=ConfigProfileResponse)
async def update_profile_includes_endpoint(
    profile_id: str,
    data: ConfigProfileIncludeUpdate,
    current_user_id: uuid.UUID = Depends(get_current_user_id),
    session: AsyncSession = Depends(get_db_session),
):
    """Update the ordered includes for a config profile."""
    profile = await get_profile_with_includes(session, uuid.UUID(profile_id))
    if profile is None:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND, detail="Profile not found"
        )
    if profile.user_id != current_user_id:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN, detail="Not authorized"
        )

    included_uuids = [uuid.UUID(inc_id) for inc_id in data.includes]
    profile = await update_includes(session, profile, included_uuids, current_user_id)

    inc_result = await session.execute(
        select(ConfigProfileInclude).where(
            ConfigProfileInclude.profile_id == profile.id
        )
    )
    direct_includes = inc_result.scalars().all()

    logger.debug("Updated includes for config profile %s", profile.id)
    return profile_to_response(profile, list(direct_includes))


@router.get("/{profile_id}/preview")
async def preview_config_profile(
    profile_id: str,
    current_user_id: uuid.UUID = Depends(get_current_user_id),
    session: AsyncSession = Depends(get_db_session),
):
    """Preview the resolved output of a config profile."""
    profile = await get_profile_with_includes(session, uuid.UUID(profile_id))
    if profile is None:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND, detail="Profile not found"
        )
    if profile.user_id != current_user_id:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN, detail="Not authorized"
        )

    try:
        resolved = await resolve_profile(session, profile.id)
    except ConfigProfileCycleError as exc:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=str(exc),
        )

    return resolved_profile_to_dict(resolved)


@router.get("/defaults/resolve")
async def resolve_default_profile_endpoint(
    project_id: str = Query(..., description="Project ID"),
    tool_type_id: str = Query(..., description="Tool type ID"),
    current_user_id: uuid.UUID = Depends(get_current_user_id),
    session: AsyncSession = Depends(get_db_session),
):
    """Resolve the default config profile for a project/tool combination."""
    return await resolve_default_profile(
        session,
        current_user_id,
        uuid.UUID(project_id),
        uuid.UUID(tool_type_id),
    )


@router.get("/defaults")
async def get_default_profiles_endpoint(
    user_id: uuid.UUID = Depends(get_current_user_id),
    session: AsyncSession = Depends(get_db_session),
) -> dict:
    """Get all default profile mappings for the current user."""
    result = await session.execute(
        select(UserConfig).where(UserConfig.user_id == user_id)
    )
    user_config = result.scalar_one_or_none()
    return {"default_profiles": user_config.default_profiles if user_config else {}}


@router.put("/defaults")
async def set_default_profiles_endpoint(
    data: DefaultProfilesUpdate,
    user_id: uuid.UUID = Depends(get_current_user_id),
    session: AsyncSession = Depends(get_db_session),
) -> dict:
    """Set default profile mappings for the current user."""
    await validate_default_profiles(session, user_id, data.default_profiles)
    user_config = await get_or_create_user_config(session, user_id)
    user_config.config = {
        **user_config.config,
        "default_profiles": data.default_profiles,
    }
    await session.commit()
    await session.refresh(user_config)
    return {"default_profiles": user_config.default_profiles}


@router.get("/defaults/{tool_type_id}")
async def get_default_profile_for_tool_type_endpoint(
    tool_type_id: str,
    user_id: uuid.UUID = Depends(get_current_user_id),
    session: AsyncSession = Depends(get_db_session),
) -> dict:
    """Get the default profile ID for a specific tool type."""
    result = await session.execute(
        select(UserConfig).where(UserConfig.user_id == user_id)
    )
    user_config = result.scalar_one_or_none()
    profile_id = user_config.default_profiles.get(tool_type_id) if user_config else None
    return {"tool_type_id": tool_type_id, "profile_id": profile_id}


@router.post("/validate-git-url", response_model=ValidateGitUrlResponse)
async def validate_git_url_endpoint(
    data: ValidateGitUrlRequest,
    current_user_id: uuid.UUID = Depends(get_current_user_id),
    session: AsyncSession = Depends(get_db_session),
) -> ValidateGitUrlResponse:
    """Validate a git remote URL and list available branches."""
    return await validate_git_url(session, current_user_id, data.url, data.ssh_key_id)
