"""Command config management API routes."""

import logging
from typing import Any

from fastapi import APIRouter, Depends, HTTPException, status
from pydantic import BaseModel
from sqlmodel import select
from sqlmodel.ext.asyncio.session import AsyncSession

from ..auth.dependencies import get_current_user
from ..database.engine import get_session
from ..database.models import CommandConfig, CommandTemplateConfig, CommandTracker, User

_LOGGER = logging.getLogger(__name__)

router = APIRouter(prefix="/api/command-configs", tags=["command-configs"])


class CommandConfigCreate(BaseModel):
    provider_type: str
    name: str
    icon: str = ""
    enabled_commands: list[str] = []
    response_mode: str = "media"
    default_count: int = 5
    rate_limits: dict[str, Any] = {}
    command_template_config_id: int | None = None


class CommandConfigUpdate(BaseModel):
    name: str | None = None
    icon: str | None = None
    enabled_commands: list[str] | None = None
    response_mode: str | None = None
    default_count: int | None = None
    rate_limits: dict[str, Any] | None = None
    command_template_config_id: int | None = None


@router.get("")
async def list_command_configs(
    user: User = Depends(get_current_user),
    session: AsyncSession = Depends(get_session),
):
    """List all command configs for the current user (including system defaults)."""
    from sqlmodel import or_
    result = await session.exec(
        select(CommandConfig).where(
            or_(CommandConfig.user_id == user.id, CommandConfig.user_id == 0)
        )
    )
    return [_config_response(c) for c in result.all()]


@router.post("", status_code=status.HTTP_201_CREATED)
async def create_command_config(
    body: CommandConfigCreate,
    user: User = Depends(get_current_user),
    session: AsyncSession = Depends(get_session),
):
    """Create a new command config."""
    # Validate provider_type
    valid_types = ("immich", "gitea")
    if body.provider_type not in valid_types:
        raise HTTPException(
            status_code=400,
            detail=f"Invalid provider_type. Must be one of: {', '.join(valid_types)}",
        )

    data = body.model_dump()
    # Auto-assign system default template if none specified
    if not data.get("command_template_config_id"):
        provider_type = data.get("provider_type", "immich")
        default_tpl = await _find_system_default_template(session, provider_type)
        if default_tpl:
            data["command_template_config_id"] = default_tpl.id

    config = CommandConfig(user_id=user.id, **data)
    session.add(config)
    await session.commit()
    await session.refresh(config)
    return _config_response(config)


@router.get("/{config_id}")
async def get_command_config(
    config_id: int,
    user: User = Depends(get_current_user),
    session: AsyncSession = Depends(get_session),
):
    """Get a single command config."""
    config = await _get_user_config(session, config_id, user.id)
    return _config_response(config)


@router.put("/{config_id}")
async def update_command_config(
    config_id: int,
    body: CommandConfigUpdate,
    user: User = Depends(get_current_user),
    session: AsyncSession = Depends(get_session),
):
    """Update a command config."""
    from sqlalchemy.orm.attributes import flag_modified
    config = await _get_user_config(session, config_id, user.id)
    for field, value in body.model_dump(exclude_unset=True).items():
        setattr(config, field, value)
        # JSON columns need explicit dirty flag for SQLAlchemy change detection
        if field in ("rate_limits", "enabled_commands"):
            flag_modified(config, field)
    session.add(config)
    await session.commit()
    await session.refresh(config)

    # Mark affected bots dirty for debounced auto-sync
    from ..services.command_sync import mark_dirty_for_config
    await mark_dirty_for_config(config.id)

    return _config_response(config)


@router.delete("/{config_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_command_config(
    config_id: int,
    user: User = Depends(get_current_user),
    session: AsyncSession = Depends(get_session),
):
    """Delete a command config. Fails if in use by any command tracker."""
    from .delete_protection import check_command_config, raise_if_used
    config = await _get_user_config(session, config_id, user.id)
    raise_if_used(await check_command_config(session, config.id), config.name)

    # Mark affected bots dirty before deleting
    from ..services.command_sync import mark_dirty_for_config
    await mark_dirty_for_config(config.id)

    await session.delete(config)
    await session.commit()


# --- Helpers ---


def _config_response(c: CommandConfig) -> dict:
    return {
        "id": c.id,
        "user_id": c.user_id,
        "provider_type": c.provider_type,
        "name": c.name,
        "icon": c.icon,
        "enabled_commands": c.enabled_commands or [],
        "response_mode": c.response_mode,
        "default_count": c.default_count,
        "rate_limits": c.rate_limits or {},
        "command_template_config_id": c.command_template_config_id,
        "created_at": c.created_at.isoformat(),
    }


async def _get_user_config(
    session: AsyncSession, config_id: int, user_id: int
) -> CommandConfig:
    config = await session.get(CommandConfig, config_id)
    if not config or (config.user_id != user_id and config.user_id != 0):
        raise HTTPException(status_code=404, detail="Command config not found")
    return config


async def _find_system_default_template(
    session: AsyncSession, provider_type: str,
) -> CommandTemplateConfig | None:
    """Find a system default (user_id=0) command template matching provider."""
    result = await session.exec(
        select(CommandTemplateConfig).where(
            CommandTemplateConfig.user_id == 0,
            CommandTemplateConfig.provider_type == provider_type,
        )
    )
    templates = result.all()
    return templates[0] if templates else None
