"""
Slot Definition API.
[AC-MRS-07,08,16] 槽位定义管理接口
"""

import logging
from typing import Annotated, Any

from fastapi import APIRouter, Depends, Query
from fastapi.responses import JSONResponse
from sqlalchemy.ext.asyncio import AsyncSession

from app.core.database import get_session
from app.core.exceptions import MissingTenantIdException
from app.core.tenant import get_tenant_id
from app.models.entities import SlotDefinitionCreate, SlotDefinitionUpdate
from app.services.slot_definition_service import SlotDefinitionService

logger = logging.getLogger(__name__)

router = APIRouter(prefix="/admin/slot-definitions", tags=["SlotDefinition"])


def get_current_tenant_id() -> str:
    """Get current tenant ID from context."""
    tenant_id = get_tenant_id()
    if not tenant_id:
        raise MissingTenantIdException()
    return tenant_id


def _slot_to_dict(slot: dict[str, Any] | Any) -> dict[str, Any]:
    """Convert slot definition to dict"""
    if isinstance(slot, dict):
        return slot
    
    return {
        "id": str(slot.id),
        "tenant_id": str(slot.tenant_id),
        "slot_key": slot.slot_key,
        "display_name": slot.display_name,
        "description": slot.description,
        "type": slot.type,
        "required": slot.required,
        # [AC-MRS-07-UPGRADE] 返回新旧字段
        "extract_strategy": slot.extract_strategy,
        "extract_strategies": slot.extract_strategies,
        "validation_rule": slot.validation_rule,
        "ask_back_prompt": slot.ask_back_prompt,
        "default_value": slot.default_value,
        "linked_field_id": str(slot.linked_field_id) if slot.linked_field_id else None,
        "created_at": slot.created_at.isoformat() if slot.created_at else None,
        "updated_at": slot.updated_at.isoformat() if slot.updated_at else None,
    }


@router.get(
    "",
    operation_id="listSlotDefinitions",
    summary="List slot definitions",
    description="获取槽位定义列表",
)
async def list_slot_definitions(
    tenant_id: Annotated[str, Depends(get_current_tenant_id)],
    session: Annotated[AsyncSession, Depends(get_session)],
    required: Annotated[bool | None, Query(
        description="按是否必填过滤"
    )] = None,
) -> JSONResponse:
    """
    列出槽位定义
    """
    logger.info(
        f"Listing slot definitions: tenant={tenant_id}, required={required}"
    )
    
    service = SlotDefinitionService(session)
    slots = await service.list_slot_definitions(tenant_id, required)
    
    return JSONResponse(
        content=[_slot_to_dict(s) for s in slots]
    )


@router.post(
    "",
    operation_id="createSlotDefinition",
    summary="Create slot definition",
    description="[AC-MRS-07,08] 创建新的槽位定义，可关联已有元数据字段",
    status_code=201,
)
async def create_slot_definition(
    tenant_id: Annotated[str, Depends(get_current_tenant_id)],
    session: Annotated[AsyncSession, Depends(get_session)],
    slot_create: SlotDefinitionCreate,
) -> JSONResponse:
    """
    [AC-MRS-07,08] 创建槽位定义
    """
    logger.info(
        f"[AC-MRS-07] Creating slot definition: "
        f"tenant={tenant_id}, slot_key={slot_create.slot_key}, "
        f"linked_field_id={slot_create.linked_field_id}"
    )
    
    service = SlotDefinitionService(session)
    
    try:
        slot = await service.create_slot_definition(tenant_id, slot_create)
        await session.commit()
    except ValueError as e:
        return JSONResponse(
            status_code=400,
            content={
                "error_code": "VALIDATION_ERROR",
                "message": str(e),
            }
        )
    
    return JSONResponse(
        status_code=201,
        content=_slot_to_dict(slot)
    )


@router.get(
    "/{id}",
    operation_id="getSlotDefinition",
    summary="Get slot definition by ID",
    description="获取单个槽位定义",
)
async def get_slot_definition(
    tenant_id: Annotated[str, Depends(get_current_tenant_id)],
    session: Annotated[AsyncSession, Depends(get_session)],
    id: str,
) -> JSONResponse:
    """
    获取单个槽位定义
    """
    logger.info(
        f"Getting slot definition: tenant={tenant_id}, id={id}"
    )
    
    service = SlotDefinitionService(session)
    slot = await service.get_slot_definition_with_field(tenant_id, id)
    
    if not slot:
        return JSONResponse(
            status_code=404,
            content={
                "error_code": "NOT_FOUND",
                "message": f"Slot definition {id} not found",
            }
        )
    
    return JSONResponse(content=slot)


@router.put(
    "/{id}",
    operation_id="updateSlotDefinition",
    summary="Update slot definition",
    description="更新槽位定义",
)
async def update_slot_definition(
    tenant_id: Annotated[str, Depends(get_current_tenant_id)],
    session: Annotated[AsyncSession, Depends(get_session)],
    id: str,
    slot_update: SlotDefinitionUpdate,
) -> JSONResponse:
    """
    更新槽位定义
    """
    logger.info(
        f"Updating slot definition: tenant={tenant_id}, id={id}"
    )
    
    service = SlotDefinitionService(session)
    
    try:
        slot = await service.update_slot_definition(tenant_id, id, slot_update)
    except ValueError as e:
        return JSONResponse(
            status_code=400,
            content={
                "error_code": "VALIDATION_ERROR",
                "message": str(e),
            }
        )
    
    if not slot:
        return JSONResponse(
            status_code=404,
            content={
                "error_code": "NOT_FOUND",
                "message": f"Slot definition {id} not found",
            }
        )
    
    await session.commit()
    
    return JSONResponse(content=_slot_to_dict(slot))


@router.delete(
    "/{id}",
    operation_id="deleteSlotDefinition",
    summary="Delete slot definition",
    description="[AC-MRS-16] 删除槽位定义，无需考虑历史数据兼容性",
    status_code=204,
)
async def delete_slot_definition(
    tenant_id: Annotated[str, Depends(get_current_tenant_id)],
    session: Annotated[AsyncSession, Depends(get_session)],
    id: str,
) -> JSONResponse:
    """
    [AC-MRS-16] 删除槽位定义
    """
    logger.info(
        f"[AC-MRS-16] Deleting slot definition: tenant={tenant_id}, id={id}"
    )
    
    service = SlotDefinitionService(session)
    success = await service.delete_slot_definition(tenant_id, id)
    
    if not success:
        return JSONResponse(
            status_code=404,
            content={
                "error_code": "NOT_FOUND",
                "message": f"Slot definition not found: {id}",
            }
        )
    
    await session.commit()
    
    return JSONResponse(status_code=204, content=None)
