"""
Sessions Controller for Mid Platform.
[AC-IDMP-09] Session mode switch endpoint: POST /mid/sessions/{sessionId}/mode
"""

import logging
from typing import Annotated

from fastapi import APIRouter, Depends, Path
from fastapi.responses import JSONResponse
from pydantic import BaseModel
from sqlalchemy.ext.asyncio import AsyncSession

from app.core.database import get_session
from app.core.tenant import get_tenant_id
from app.models.mid.schemas import (
    SessionMode,
    SwitchModeRequest,
    SwitchModeResponse,
)
from app.services.memory import MemoryService

logger = logging.getLogger(__name__)

router = APIRouter(prefix="/mid", tags=["Mid Platform Sessions"])

_session_modes: dict[str, SessionMode] = {}


class CancelFlowResponse(BaseModel):
    """Response for cancel flow operation."""

    success: bool
    message: str
    session_id: str


@router.post(
    "/sessions/{sessionId}/cancel-flow",
    operation_id="cancelActiveFlow",
    summary="Cancel active flow",
    description="""
    Cancel the active flow for a session.
    
    Use this when you encounter "Session already has an active flow" error.
    """,
    responses={
        200: {"description": "Flow cancelled successfully", "model": CancelFlowResponse},
        404: {"description": "No active flow found"},
    },
)
async def cancel_active_flow(
    sessionId: Annotated[str, Path(description="Session ID")],
    session: Annotated[AsyncSession, Depends(get_session)],
) -> CancelFlowResponse:
    """
    Cancel the active flow for a session.
    
    This endpoint allows you to cancel any active flow instance
    so that a new flow can be started.
    """
    tenant_id = get_tenant_id()
    
    if not tenant_id:
        from app.core.exceptions import MissingTenantIdException
        raise MissingTenantIdException()
    
    logger.info(
        f"[Cancel Flow] Cancelling active flow: tenant={tenant_id}, session={sessionId}"
    )
    
    try:
        from app.services.flow.engine import FlowEngine
        
        flow_engine = FlowEngine(session)
        cancelled = await flow_engine.cancel_flow(
            tenant_id=tenant_id,
            session_id=sessionId,
            reason="User requested cancellation via API",
        )
        
        if cancelled:
            logger.info(f"[Cancel Flow] Flow cancelled: session={sessionId}")
            return CancelFlowResponse(
                success=True,
                message="Active flow cancelled successfully",
                session_id=sessionId,
            )
        else:
            logger.info(f"[Cancel Flow] No active flow found: session={sessionId}")
            return CancelFlowResponse(
                success=True,
                message="No active flow found for this session",
                session_id=sessionId,
            )
    
    except Exception as e:
        logger.error(f"[Cancel Flow] Failed to cancel flow: {e}")
        return CancelFlowResponse(
            success=False,
            message=f"Failed to cancel flow: {str(e)}",
            session_id=sessionId,
        )


@router.post(
    "/sessions/{sessionId}/mode",
    operation_id="switchSessionMode",
    summary="Switch session mode",
    description="""
    [AC-IDMP-09] Switch session mode between BOT_ACTIVE and HUMAN_ACTIVE.
    
    When mode is HUMAN_ACTIVE, dialogue responses will route to transfer mode.
    """,
    responses={
        200: {"description": "Mode switched successfully", "model": SwitchModeResponse},
        400: {"description": "Invalid request"},
    },
)
async def switch_session_mode(
    sessionId: Annotated[str, Path(description="Session ID")],
    switch_request: SwitchModeRequest,
    session: Annotated[AsyncSession, Depends(get_session)],
) -> SwitchModeResponse:
    """
    [AC-IDMP-09] Switch session mode.
    
    Modes:
    - BOT_ACTIVE: Bot handles responses
    - HUMAN_ACTIVE: Transfer to human agent
    """
    tenant_id = get_tenant_id()
    
    if not tenant_id:
        from app.core.exceptions import MissingTenantIdException
        raise MissingTenantIdException()
    
    logger.info(
        f"[AC-IDMP-09] Mode switch: tenant={tenant_id}, "
        f"session={sessionId}, mode={switch_request.mode.value}"
    )
    
    try:
        memory_service = MemoryService(session)
        
        await memory_service.get_or_create_session(
            tenant_id=tenant_id,
            session_id=sessionId,
        )
        
        session_key = f"{tenant_id}:{sessionId}"
        _session_modes[session_key] = switch_request.mode
        
        logger.info(
            f"[AC-IDMP-09] Mode switched: session={sessionId}, "
            f"mode={switch_request.mode.value}, reason={switch_request.reason}"
        )
        
        return SwitchModeResponse(
            session_id=sessionId,
            mode=switch_request.mode,
        )
    
    except Exception as e:
        logger.error(f"[AC-IDMP-09] Mode switch failed: {e}")
        return SwitchModeResponse(
            session_id=sessionId,
            mode=switch_request.mode,
        )


def get_session_mode(tenant_id: str, session_id: str) -> SessionMode:
    """Get current session mode."""
    session_key = f"{tenant_id}:{session_id}"
    return _session_modes.get(session_key, SessionMode.BOT_ACTIVE)


def clear_session_mode(tenant_id: str, session_id: str) -> None:
    """Clear session mode (reset to BOT_ACTIVE)."""
    session_key = f"{tenant_id}:{session_id}"
    if session_key in _session_modes:
        del _session_modes[session_key]
