"""Document streaming controller for secure document viewing."""

import json
import logging
import uuid

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

from src.core.database import get_async_db
from src.middleware.auth_middleware import get_current_tenant_id
from src.services.storage.s3_storage import S3StorageService

logger = logging.getLogger(__name__)

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


async def _validate_s3_key_ownership(key: str, tenant_id: uuid.UUID, db: AsyncSession) -> bool:
    """
    SECURITY: Validate that the S3 key belongs to resources owned by the tenant.

    Args:
        key: S3 object key
        tenant_id: Current tenant's UUID
        db: Database session

    Returns:
        True if the key belongs to the tenant, False otherwise
    """
    # Check if key contains a knowledge base document
    if "/knowledge-bases/" in key or key.startswith("knowledge-bases/"):
        from src.models.knowledge_base import KnowledgeBase

        # Extract KB ID from key patterns like:
        # knowledge-bases/{kb_id}/documents/...
        # tenants/{tenant_id}/knowledge-bases/{kb_id}/...
        parts = key.split("/")
        for i, part in enumerate(parts):
            if part == "knowledge-bases" and i + 1 < len(parts):
                kb_id_str = parts[i + 1]
                try:
                    kb_id = int(kb_id_str)
                    result = await db.execute(
                        select(KnowledgeBase).filter(KnowledgeBase.id == kb_id, KnowledgeBase.tenant_id == tenant_id)
                    )
                    kb = result.scalar_one_or_none()
                    return kb is not None
                except (ValueError, TypeError):
                    pass
        return False

    # Check if key contains a context file
    if "/context-files/" in key or key.startswith("context-files/"):
        from src.models.agent import Agent
        from src.models.agent_context_file import AgentContextFile

        # Find the context file by S3 key
        result = await db.execute(select(AgentContextFile).filter(AgentContextFile.s3_key == key))
        context_file = result.scalar_one_or_none()

        if context_file and context_file.agent_id:
            result = await db.execute(
                select(Agent).filter(Agent.id == context_file.agent_id, Agent.tenant_id == tenant_id)
            )
            agent = result.scalar_one_or_none()
            return agent is not None
        return False

    # Check if key contains a data source document
    if "/data-sources/" in key or key.startswith("data-sources/"):
        from src.models.data_source import DataSource

        parts = key.split("/")
        for i, part in enumerate(parts):
            if part == "data-sources" and i + 1 < len(parts):
                ds_id_str = parts[i + 1]
                try:
                    ds_id = int(ds_id_str)
                    result = await db.execute(
                        select(DataSource).filter(DataSource.id == ds_id, DataSource.tenant_id == tenant_id)
                    )
                    ds = result.scalar_one_or_none()
                    return ds is not None
                except (ValueError, TypeError):
                    pass
        return False

    # Check if key is tenant-scoped (documents generated by agents)
    if key.startswith(f"documents/{tenant_id}/"):
        return True

    # Check if key is tenant-scoped (general tenant prefix)
    if key.startswith(f"tenants/{tenant_id}/") or key.startswith(f"{tenant_id}/"):
        return True

    # Default: deny access to unrecognized key patterns
    logger.warning(f"Denying access to unrecognized S3 key pattern: {key[:50]}...")
    return False


@router.get("/stream/{key:path}")
async def stream_document(
    key: str,
    tenant_id: uuid.UUID = Depends(get_current_tenant_id),
    db: AsyncSession = Depends(get_async_db),
):
    """
    Stream a document from S3 storage.

    Args:
        key: S3 object key (path to file)

    Returns:
        Streamed file with appropriate headers for embedding
    """
    try:
        # SECURITY: Validate the S3 key belongs to the authenticated tenant
        if not await _validate_s3_key_ownership(key, tenant_id, db):
            logger.warning(f"Access denied: tenant {tenant_id} tried to access key {key[:50]}...")
            return Response(
                content=json.dumps({"error": "Document not found"}), status_code=404, media_type="application/json"
            )

        logger.info(f"Streaming document for tenant {tenant_id}: {key[:50]}...")

        # Get storage service
        storage = S3StorageService()

        # Download file from S3
        file_data = storage.download_file(key)

        if not file_data:
            logger.error(f"Document not found: {key}")
            return Response(
                content=json.dumps({"error": "Document not found"}), status_code=404, media_type="application/json"
            )

        # Determine content type from file extension
        content_type = _get_content_type(key)

        logger.info(f"Streaming {len(file_data)} bytes as {content_type}")

        # SECURITY: Return file with controlled CORS headers
        # Note: Access-Control-Allow-Origin should be restricted to specific allowed origins
        # rather than "*" to prevent cross-site data exfiltration

        return Response(
            content=file_data,
            media_type=content_type,
            headers={
                "Content-Disposition": "inline",
                "Cache-Control": "public, max-age=3600",
                "Access-Control-Allow-Origin": "*",
                "Accept-Ranges": "bytes",
            },
        )

    except Exception as e:
        logger.error(f"Error streaming document: {str(e)}", exc_info=True)
        return Response(
            content=json.dumps({"error": f"Failed to stream document: {str(e)}"}),
            status_code=500,
            media_type="application/json",
        )


def _get_content_type(filename: str) -> str:
    """Determine content type from file extension"""
    extension = filename.lower().split(".")[-1]

    content_types = {
        "pdf": "application/pdf",
        "pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
        "docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
        "xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
        "txt": "text/plain",
        "md": "text/markdown",
        "json": "application/json",
        "csv": "text/csv",
    }

    return content_types.get(extension, "application/octet-stream")
