"""Document upload and retrieval endpoints."""

from typing import Optional, List
from uuid import UUID

from fastapi import APIRouter, Depends, File, Form, HTTPException, UploadFile, status
from sqlalchemy.orm import Session

from app.api.deps import get_current_admin, get_current_user, get_db
from app.config import settings
from app.models.document import Document, DocumentStatus, DocumentType
from app.models.user import UserType
from app.schemas.common import SuccessResponse
from app.schemas.document import DocumentCreate, DocumentResponse, DocumentUpdate
import io

from imagekitio import ImageKit

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


async def upload_to_imagekit(file_content: bytes, file_name: str, folder: str = "documents") -> str:
    """
    Upload file to ImageKit and return URL.
    Uses ImageKit Python SDK v5.x (imagekitio).
    The SDK sends uploads to https://api.imagekit.io (its default base_url).
    Do NOT pass the CDN endpoint URL as base_url — that causes a 403 CloudFront error.
    Pass bytes wrapped in io.BytesIO (file-like object) — the SDK expects io.IOBase or bytes.
    """
    # If ImageKit keys are not configured, fall back to deterministic URL pattern
    if not settings.imagekit_public_key or not settings.imagekit_private_key:
        return f"{settings.imagekit_endpoint_url.rstrip('/')}/{folder}/{file_name}"

    try:
        # Ensure file_content is actually bytes, not a string
        if isinstance(file_content, str):
            file_content = file_content.encode('utf-8')
        elif not isinstance(file_content, bytes):
            raise ValueError(f"file_content must be bytes or str, got {type(file_content)}")

        # Initialize ImageKit client — only private_key is needed for server-side uploads.
        # Do NOT override base_url with the CDN endpoint; the SDK defaults to
        # https://api.imagekit.io which is the correct upload API.
        imagekit = ImageKit(private_key=settings.imagekit_private_key)

        # Wrap bytes in BytesIO to create a file-like object (io.IOBase)
        # The SDK accepts bytes, io.IOBase, PathLike, or tuple
        file_obj = io.BytesIO(file_content)

        # Upload via the files resource
        upload_response = imagekit.files.upload(
            file=file_obj,  # File-like object (io.BytesIO)
            file_name=file_name,
            folder=folder,
            public_key=settings.imagekit_public_key,
            use_unique_file_name=True,
        )

        # Extract URL from response
        if upload_response and hasattr(upload_response, "url") and upload_response.url:
            return upload_response.url
        elif upload_response and hasattr(upload_response, "file_path") and upload_response.file_path:
            return f"{settings.imagekit_endpoint_url.rstrip('/')}/{upload_response.file_path}"
        # Fallback
        return f"{settings.imagekit_endpoint_url.rstrip('/')}/{folder}/{file_name}"
    except Exception as e:
        raise RuntimeError(f"ImageKit upload failed: {e}")


@router.post("/upload", response_model=SuccessResponse, status_code=status.HTTP_201_CREATED)
async def upload_document(
    file: UploadFile = File(...),
    document_type: DocumentType = Form(...),
    description: Optional[str] = Form(None),
    application_id: Optional[UUID] = Form(None),
    db: Session = Depends(get_db),
    current_user_data: dict = Depends(get_current_user),
):
    """Upload a document (ID, certificates, transcripts, etc.) to storage."""
    # Verify user
    user_data = current_user_data
    if user_data.get("type") != "user":
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Authentication required",
        )
    
    user = user_data.get("user")
    user_id = user.id
    
    # Read file content
    file_content = await file.read()
    file_size = len(file_content)
    
    # Upload to ImageKit (or other storage)
    try:
        file_url = await upload_to_imagekit(
            file_content=file_content,
            file_name=file.filename or f"document_{user_id}_{document_type.value}",
            folder="documents"
        )
    except Exception as e:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Failed to upload file: {str(e)}",
        )
    
    # Create document record
    document = Document(
        user_id=user_id,
        application_id=application_id,
        document_type=document_type,
        file_name=file.filename or "unknown",
        file_url=file_url,
        file_size=file_size,
        mime_type=file.content_type,
        description=description,
        status=DocumentStatus.PENDING,
    )
    
    db.add(document)
    db.commit()
    db.refresh(document)
    
    return SuccessResponse(
        data=DocumentResponse.model_validate(document).model_dump(),
        message="Document uploaded successfully",
    )


@router.get("/{document_id}", response_model=SuccessResponse)
async def get_document(
    document_id: UUID,
    db: Session = Depends(get_db),
    current_user_data: dict = Depends(get_current_user),
):
    """Get document details and signed URL for download."""
    document = db.query(Document).filter(Document.id == document_id).first()
    if not document:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Document not found",
        )
    
    # Verify user has permission
    user_data = current_user_data
    if user_data.get("type") == "user":
        user = user_data.get("user")
        # Users can only see their own documents, unless admin
        if user.user_type != UserType.SENATE_ADMIN and str(document.user_id) != str(user.id):
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail="You can only access your own documents",
            )
    
    # TODO: Generate signed URL for secure download
    # For now, return the file URL directly
    # In production, use ImageKit signed URLs or S3 presigned URLs
    
    document_data = DocumentResponse.model_validate(document).model_dump()
    document_data["download_url"] = document.file_url  # In production, generate signed URL
    
    return SuccessResponse(
        data=document_data,
        message="Document retrieved successfully",
    )


@router.get("", response_model=SuccessResponse)
async def list_documents(
    user_id: Optional[UUID] = None,
    application_id: Optional[UUID] = None,
    document_type: Optional[DocumentType] = None,
    status: Optional[DocumentStatus] = None,
    db: Session = Depends(get_db),
    current_user_data: dict = Depends(get_current_user),
):
    """List documents with optional filters."""
    query = db.query(Document)
    
    # Users can only see their own documents, unless admin
    user_data = current_user_data
    if user_data.get("type") == "user":
        user = user_data.get("user")
        if user.user_type != UserType.SENATE_ADMIN:
            query = query.filter(Document.user_id == user.id)
    
    if user_id:
        query = query.filter(Document.user_id == user_id)
    if application_id:
        query = query.filter(Document.application_id == application_id)
    if document_type:
        query = query.filter(Document.document_type == document_type)
    if status:
        query = query.filter(Document.status == status)
    
    documents = query.order_by(Document.created_at.desc()).all()
    
    return SuccessResponse(
        data=[DocumentResponse.model_validate(d).model_dump() for d in documents],
        message="Documents retrieved successfully",
    )


@router.put("/{document_id}/verify", response_model=SuccessResponse)
async def verify_document(
    document_id: UUID,
    update_data: DocumentUpdate,
    db: Session = Depends(get_db),
    current_admin = Depends(get_current_admin),
):
    """Verify or reject a document (admin only)."""
    from datetime import datetime
    
    document = db.query(Document).filter(Document.id == document_id).first()
    if not document:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Document not found",
        )
    
    if update_data.status:
        document.status = update_data.status
        if update_data.status == DocumentStatus.VERIFIED:
            document.verified_by = current_admin.id
            document.verified_at = datetime.utcnow()
        elif update_data.status == DocumentStatus.REJECTED:
            document.verified_by = current_admin.id
            document.verified_at = datetime.utcnow()
    
    if update_data.verification_notes:
        document.verification_notes = update_data.verification_notes
    
    db.commit()
    db.refresh(document)
    
    return SuccessResponse(
        data=DocumentResponse.model_validate(document).model_dump(),
        message="Document verification updated successfully",
    )
