"""Server profiles API router."""

from datetime import UTC, datetime

from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.ext.asyncio import AsyncSession
from sqlmodel import select

from mlx_manager.config import settings
from mlx_manager.database import get_db
from mlx_manager.dependencies import get_profile_or_404
from mlx_manager.models import (
    ServerProfile,
    ServerProfileCreate,
    ServerProfileResponse,
    ServerProfileUpdate,
)

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


@router.get("", response_model=list[ServerProfileResponse])
async def list_profiles(session: AsyncSession = Depends(get_db)):
    """List all server profiles."""
    result = await session.execute(select(ServerProfile))
    profiles = result.scalars().all()
    return profiles


@router.get("/next-port")
async def get_next_port(session: AsyncSession = Depends(get_db)):
    """Get the next available port."""
    from sqlalchemy import desc

    # SQLModel types port as int, but it's a Column at runtime
    result = await session.execute(
        select(ServerProfile.port).order_by(desc(ServerProfile.port))  # type: ignore[arg-type]
    )
    ports = result.scalars().all()

    if not ports:
        return {"port": settings.default_port_start}

    # Find the next available port
    next_port = settings.default_port_start
    for port in sorted(ports):
        if port >= next_port:
            next_port = port + 1

    return {"port": next_port}


@router.get("/{profile_id}", response_model=ServerProfileResponse)
async def get_profile(profile: ServerProfile = Depends(get_profile_or_404)):
    """Get a specific profile."""
    return profile


@router.post("", response_model=ServerProfileResponse, status_code=201)
async def create_profile(
    profile_data: ServerProfileCreate, session: AsyncSession = Depends(get_db)
):
    """Create a new server profile."""
    # Check for unique name
    result = await session.execute(
        select(ServerProfile).where(ServerProfile.name == profile_data.name)
    )
    if result.scalar_one_or_none():
        raise HTTPException(status_code=409, detail="Profile name already exists")

    # Check for unique port
    result = await session.execute(
        select(ServerProfile).where(ServerProfile.port == profile_data.port)
    )
    if result.scalar_one_or_none():
        raise HTTPException(status_code=409, detail="Port already in use by another profile")

    profile = ServerProfile.model_validate(profile_data)
    session.add(profile)
    await session.commit()
    await session.refresh(profile)

    return profile


@router.put("/{profile_id}", response_model=ServerProfileResponse)
async def update_profile(
    profile_id: int,
    profile_data: ServerProfileUpdate,
    session: AsyncSession = Depends(get_db),
):
    """Update a server profile."""
    result = await session.execute(select(ServerProfile).where(ServerProfile.id == profile_id))
    profile = result.scalar_one_or_none()

    if not profile:
        raise HTTPException(status_code=404, detail="Profile not found")

    # Check for name conflict
    if profile_data.name and profile_data.name != profile.name:
        result = await session.execute(
            select(ServerProfile).where(ServerProfile.name == profile_data.name)
        )
        if result.scalar_one_or_none():
            raise HTTPException(status_code=409, detail="Profile name already exists")

    # Check for port conflict
    if profile_data.port and profile_data.port != profile.port:
        result = await session.execute(
            select(ServerProfile).where(ServerProfile.port == profile_data.port)
        )
        if result.scalar_one_or_none():
            raise HTTPException(status_code=409, detail="Port already in use by another profile")

    # Update fields
    update_data = profile_data.model_dump(exclude_unset=True)
    for key, value in update_data.items():
        setattr(profile, key, value)

    profile.updated_at = datetime.now(tz=UTC)
    session.add(profile)
    await session.commit()
    await session.refresh(profile)

    return profile


@router.delete("/{profile_id}", status_code=204)
async def delete_profile(
    profile: ServerProfile = Depends(get_profile_or_404),
    session: AsyncSession = Depends(get_db),
):
    """Delete a server profile."""
    await session.delete(profile)
    await session.commit()


@router.post("/{profile_id}/duplicate", response_model=ServerProfileResponse, status_code=201)
async def duplicate_profile(
    new_name: str,
    profile: ServerProfile = Depends(get_profile_or_404),
    session: AsyncSession = Depends(get_db),
):
    """Duplicate a profile with a new name."""
    # Check for name conflict
    result = await session.execute(select(ServerProfile).where(ServerProfile.name == new_name))
    if result.scalar_one_or_none():
        raise HTTPException(status_code=409, detail="Profile name already exists")

    # Get next available port
    from sqlalchemy import desc

    # SQLModel types port as int, but it's a Column at runtime
    port_result = await session.execute(
        select(ServerProfile.port).order_by(desc(ServerProfile.port))  # type: ignore[arg-type]
    )
    ports: list[int] = list(port_result.scalars().all())
    next_port = ports[0] + 1 if ports else settings.default_port_start

    # Create new profile
    new_profile = ServerProfile(
        name=new_name,
        description=profile.description,
        model_path=profile.model_path,
        model_type=profile.model_type,
        port=next_port,
        host=profile.host,
        context_length=profile.context_length,
        max_concurrency=profile.max_concurrency,
        queue_timeout=profile.queue_timeout,
        queue_size=profile.queue_size,
        tool_call_parser=profile.tool_call_parser,
        reasoning_parser=profile.reasoning_parser,
        enable_auto_tool_choice=profile.enable_auto_tool_choice,
        trust_remote_code=profile.trust_remote_code,
        chat_template_file=profile.chat_template_file,
        log_level=profile.log_level,
        log_file=profile.log_file,
        no_log_file=profile.no_log_file,
        auto_start=False,  # Don't copy auto_start
    )

    session.add(new_profile)
    await session.commit()
    await session.refresh(new_profile)

    return new_profile
