import base64
from uuid import UUID

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

from app.core.database import get_db
from app.api.deps import get_current_active_user
from app.models import User
from app.models.session import Session
from app.models.supporting_data import SessionSupportingData
from app.schemas.supporting_data import (
    SupportingDataCreate,
    SupportingDataUpdate,
    SupportingDataResponse,
)

router = APIRouter(prefix="/sessions", tags=["supporting-data"])

MAX_ITEMS_PER_SESSION = 20
MAX_TEXT_SNIPPET_CHARS = 50_000
MAX_SCREENSHOT_RAW_BYTES = 2 * 1024 * 1024  # 2MB


async def _check_session_access(user: User, session: Session, db: AsyncSession) -> None:
    """Verify user has access to the session (owner, team admin, or super admin)."""
    if user.is_super_admin:
        return
    if session.user_id == user.id:
        return
    # Team admins can only access sessions from their own team members
    if user.is_team_admin and user.team_id is not None:
        session_owner = await db.get(User, session.user_id)
        if session_owner and session_owner.team_id == user.team_id:
            return
    raise HTTPException(status_code=403, detail="Access denied")


async def _get_session_or_404(session_id: UUID, db: AsyncSession) -> Session:
    """Fetch session by ID or raise 404."""
    result = await db.execute(select(Session).where(Session.id == session_id))
    session = result.scalar_one_or_none()
    if not session:
        raise HTTPException(status_code=404, detail="Session not found")
    return session


@router.post(
    "/{session_id}/supporting-data",
    response_model=SupportingDataResponse,
    status_code=status.HTTP_201_CREATED,
)
async def create_supporting_data(
    session_id: UUID,
    data: SupportingDataCreate,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_active_user),
):
    """Add a supporting data item (text snippet or screenshot) to a session."""
    session = await _get_session_or_404(session_id, db)
    await _check_session_access(current_user, session, db)

    # Check item limit
    count_result = await db.execute(
        select(func.count()).select_from(SessionSupportingData).where(
            SessionSupportingData.session_id == session_id
        )
    )
    current_count = count_result.scalar() or 0
    if current_count >= MAX_ITEMS_PER_SESSION:
        raise HTTPException(
            status_code=400,
            detail=f"Maximum {MAX_ITEMS_PER_SESSION} supporting data items per session",
        )

    # Validate content size based on type
    if data.data_type == "text_snippet":
        if len(data.content) > MAX_TEXT_SNIPPET_CHARS:
            raise HTTPException(
                status_code=400,
                detail=f"Text snippet exceeds maximum {MAX_TEXT_SNIPPET_CHARS} characters",
            )
    elif data.data_type == "screenshot":
        try:
            raw_bytes = base64.b64decode(data.content)
        except Exception:
            raise HTTPException(status_code=400, detail="Invalid base64 content for screenshot")
        if len(raw_bytes) > MAX_SCREENSHOT_RAW_BYTES:
            raise HTTPException(
                status_code=400,
                detail=f"Screenshot exceeds maximum {MAX_SCREENSHOT_RAW_BYTES // (1024 * 1024)}MB raw size",
            )

    # Auto-increment sort_order
    max_order_result = await db.execute(
        select(func.max(SessionSupportingData.sort_order)).where(
            SessionSupportingData.session_id == session_id
        )
    )
    max_order = max_order_result.scalar()
    next_order = (max_order or 0) + 1

    item = SessionSupportingData(
        session_id=session_id,
        account_id=session.account_id,
        label=data.label,
        data_type=data.data_type,
        content=data.content,
        content_type=data.content_type,
        sort_order=next_order,
    )
    db.add(item)
    await db.commit()
    await db.refresh(item)

    return item


@router.get(
    "/{session_id}/supporting-data",
    response_model=list[SupportingDataResponse],
)
async def list_supporting_data(
    session_id: UUID,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_active_user),
):
    """List all supporting data items for a session, ordered by sort_order."""
    session = await _get_session_or_404(session_id, db)
    await _check_session_access(current_user, session, db)

    result = await db.execute(
        select(SessionSupportingData)
        .where(SessionSupportingData.session_id == session_id)
        .order_by(SessionSupportingData.sort_order)
    )
    return result.scalars().all()


@router.patch(
    "/{session_id}/supporting-data/{item_id}",
    response_model=SupportingDataResponse,
)
async def update_supporting_data(
    session_id: UUID,
    item_id: UUID,
    data: SupportingDataUpdate,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_active_user),
):
    """Update a supporting data item's label or content."""
    session = await _get_session_or_404(session_id, db)
    await _check_session_access(current_user, session, db)

    result = await db.execute(
        select(SessionSupportingData).where(
            SessionSupportingData.id == item_id,
            SessionSupportingData.session_id == session_id,
        )
    )
    item = result.scalar_one_or_none()
    if not item:
        raise HTTPException(status_code=404, detail="Supporting data item not found")

    if data.label is not None:
        item.label = data.label
    if data.content is not None:
        item.content = data.content

    await db.commit()
    await db.refresh(item)

    return item


@router.delete(
    "/{session_id}/supporting-data/{item_id}",
    status_code=status.HTTP_204_NO_CONTENT,
)
async def delete_supporting_data(
    session_id: UUID,
    item_id: UUID,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_active_user),
):
    """Remove a supporting data item from a session."""
    session = await _get_session_or_404(session_id, db)
    await _check_session_access(current_user, session, db)

    result = await db.execute(
        select(SessionSupportingData).where(
            SessionSupportingData.id == item_id,
            SessionSupportingData.session_id == session_id,
        )
    )
    item = result.scalar_one_or_none()
    if not item:
        raise HTTPException(status_code=404, detail="Supporting data item not found")

    await db.delete(item)
    await db.commit()
