"""
Custom Prompt CRUD routes for Pro users
Story 3.11: Custom Prompts - Endpoint CRUD
"""

import logging
from datetime import datetime, timezone
from typing import Optional

from fastapi import APIRouter, Depends, Query
from fastapi.responses import JSONResponse

from routes.deps import require_pro_user, ProUser
from database.connection import get_sync_session
from database.models import CustomPrompt
from schemas.prompt_schemas import (
    PromptCreate,
    PromptUpdate,
    PromptResponse,
    PromptListItem,
    PromptListResponse,
    PromptDetailResponse,
)

logger = logging.getLogger(__name__)

router = APIRouter(prefix="/api/v1/prompts", tags=["Prompts v1"])

DEFAULT_PAGE_SIZE = 50
MAX_PAGE_SIZE = 100


def _validate_uuid(prompt_id: str) -> tuple[bool, dict | None]:
    """Validate UUID format. Returns (is_valid, error_response)."""
    import uuid as uuid_lib

    try:
        uuid_lib.UUID(prompt_id)
        return True, None
    except ValueError:
        return False, {
            "error": "INVALID_PROMPT_ID",
            "message": "Invalid prompt ID format.",
        }


def _format_prompt(prompt: CustomPrompt) -> dict:
    """Format a CustomPrompt for JSON response."""
    return {
        "id": prompt.id,
        "name": prompt.name,
        "content": prompt.content,
        "created_at": prompt.created_at.isoformat() if prompt.created_at else None,
        "updated_at": prompt.updated_at.isoformat() if prompt.updated_at else None,
    }


def _format_prompt_list_item(prompt: CustomPrompt) -> dict:
    """Format a CustomPrompt for list view with content preview."""
    content_preview = prompt.content[:100] if prompt.content else ""
    return {
        "id": prompt.id,
        "name": prompt.name,
        "content_preview": content_preview,
        "created_at": prompt.created_at.isoformat() if prompt.created_at else None,
        "updated_at": prompt.updated_at.isoformat() if prompt.updated_at else None,
    }


@router.post(
    "",
    response_model=PromptDetailResponse,
    status_code=201,
    summary="Créer un prompt",
    description="""
    Crée un nouveau prompt système personnalisé.
    
    **Restriction:** Uniquement disponible pour les utilisateurs Pro.
    
    **Exemple de requête:**
    ```json
    {
        "name": "Prompt Technique FR-EN",
        "content": "Tu es un traducteur technique expert. Traduis en préservant la terminologie technique..."
    }
    ```
    """,
)
async def create_prompt(
    body: PromptCreate,
    user: ProUser = Depends(require_pro_user),
):
    """Create a new prompt for the authenticated Pro user."""
    try:
        with get_sync_session() as session:
            prompt = CustomPrompt(
                user_id=user.id,
                name=body.name,
                content=body.content,
                created_at=datetime.now(timezone.utc),
                updated_at=datetime.now(timezone.utc),
            )

            session.add(prompt)
            session.commit()
            session.refresh(prompt)

            logger.info(
                f"Prompt created: id={prompt.id}, user_id={user.id}, name={prompt.name}"
            )

            return JSONResponse(
                status_code=201,
                content={
                    "data": _format_prompt(prompt),
                    "meta": {},
                },
            )
    except Exception as e:
        logger.error(f"Failed to create prompt for user {user.id}: {e}")
        return JSONResponse(
            status_code=500,
            content={
                "error": "DATABASE_ERROR",
                "message": "An error occurred while creating the prompt.",
            },
        )


@router.get(
    "",
    response_model=PromptListResponse,
    summary="Lister les prompts",
    description="Retourne la liste paginée des prompts de l'utilisateur.",
)
async def list_prompts(
    page: int = Query(1, ge=1, description="Numéro de page"),
    per_page: int = Query(
        DEFAULT_PAGE_SIZE, ge=1, le=MAX_PAGE_SIZE, description="Éléments par page"
    ),
    user: ProUser = Depends(require_pro_user),
):
    """List all prompts for the authenticated Pro user with pagination."""
    try:
        with get_sync_session() as session:
            total_count = (
                session.query(CustomPrompt)
                .filter(CustomPrompt.user_id == user.id)
                .count()
            )

            offset = (page - 1) * per_page
            prompts = (
                session.query(CustomPrompt)
                .filter(CustomPrompt.user_id == user.id)
                .order_by(CustomPrompt.created_at.desc())
                .offset(offset)
                .limit(per_page)
                .all()
            )

            items = [
                PromptListItem(
                    id=p.id,
                    name=p.name,
                    content_preview=p.content[:100] if p.content else "",
                    created_at=p.created_at,
                    updated_at=p.updated_at,
                )
                for p in prompts
            ]

            total_pages = (total_count + per_page - 1) // per_page

            return JSONResponse(
                status_code=200,
                content={
                    "data": [item.model_dump(mode="json") for item in items],
                    "meta": {
                        "total": total_count,
                        "page": page,
                        "per_page": per_page,
                        "total_pages": total_pages,
                    },
                },
            )
    except Exception as e:
        logger.error(f"Failed to list prompts for user {user.id}: {e}")
        return JSONResponse(
            status_code=500,
            content={
                "error": "DATABASE_ERROR",
                "message": "An error occurred while retrieving prompts.",
            },
        )


@router.get(
    "/{prompt_id}",
    response_model=PromptDetailResponse,
    summary="Détail d'un prompt",
    description="Retourne les détails d'un prompt spécifique.",
)
async def get_prompt(
    prompt_id: str,
    user: ProUser = Depends(require_pro_user),
):
    """Get a specific prompt by ID."""
    is_valid, error = _validate_uuid(prompt_id)
    if not is_valid:
        return JSONResponse(status_code=400, content=error)

    try:
        with get_sync_session() as session:
            prompt = (
                session.query(CustomPrompt)
                .filter(CustomPrompt.id == prompt_id, CustomPrompt.user_id == user.id)
                .first()
            )

            if not prompt:
                return JSONResponse(
                    status_code=404,
                    content={
                        "error": "PROMPT_NOT_FOUND",
                        "message": "Prompt not found or you do not have access to this resource.",
                    },
                )

            return JSONResponse(
                status_code=200,
                content={
                    "data": _format_prompt(prompt),
                    "meta": {},
                },
            )
    except Exception as e:
        logger.error(f"Failed to get prompt {prompt_id}: {e}")
        return JSONResponse(
            status_code=500,
            content={
                "error": "DATABASE_ERROR",
                "message": "An error occurred.",
            },
        )


@router.patch(
    "/{prompt_id}",
    response_model=PromptDetailResponse,
    summary="Mettre à jour un prompt",
    description="Met à jour le nom et/ou le contenu d'un prompt existant.",
)
async def update_prompt(
    prompt_id: str,
    body: PromptUpdate,
    user: ProUser = Depends(require_pro_user),
):
    """Update a prompt's name and/or content."""
    if not body.has_updates():
        return JSONResponse(
            status_code=400,
            content={
                "error": "NO_UPDATE_FIELDS",
                "message": "At least one field (name or content) must be provided.",
            },
        )

    is_valid, error = _validate_uuid(prompt_id)
    if not is_valid:
        return JSONResponse(status_code=400, content=error)

    try:
        with get_sync_session() as session:
            prompt = (
                session.query(CustomPrompt)
                .filter(CustomPrompt.id == prompt_id, CustomPrompt.user_id == user.id)
                .first()
            )

            if not prompt:
                return JSONResponse(
                    status_code=404,
                    content={
                        "error": "PROMPT_NOT_FOUND",
                        "message": "Prompt not found or you do not have access to this resource.",
                    },
                )

            old_name = prompt.name

            if body.name is not None:
                prompt.name = body.name

            if body.content is not None:
                prompt.content = body.content

            prompt.updated_at = datetime.now(timezone.utc)
            session.commit()
            session.refresh(prompt)

            logger.info(
                f"Prompt updated: id={prompt.id}, user_id={user.id}, "
                f"old_name={old_name}, new_name={prompt.name}"
            )

            return JSONResponse(
                status_code=200,
                content={
                    "data": _format_prompt(prompt),
                    "meta": {},
                },
            )
    except Exception as e:
        logger.error(f"Failed to update prompt {prompt_id}: {e}")
        return JSONResponse(
            status_code=500,
            content={
                "error": "DATABASE_ERROR",
                "message": "An error occurred while updating.",
            },
        )


@router.delete(
    "/{prompt_id}",
    status_code=204,
    summary="Supprimer un prompt",
    description="Supprime un prompt.",
)
async def delete_prompt(
    prompt_id: str,
    user: ProUser = Depends(require_pro_user),
):
    """Delete a prompt."""
    is_valid, error = _validate_uuid(prompt_id)
    if not is_valid:
        return JSONResponse(status_code=400, content=error)

    try:
        with get_sync_session() as session:
            prompt = (
                session.query(CustomPrompt)
                .filter(CustomPrompt.id == prompt_id, CustomPrompt.user_id == user.id)
                .first()
            )

            if not prompt:
                return JSONResponse(
                    status_code=404,
                    content={
                        "error": "PROMPT_NOT_FOUND",
                        "message": "Prompt not found or you do not have access to this resource.",
                    },
                )

            prompt_name = prompt.name
            session.delete(prompt)
            session.commit()

            logger.info(
                f"Prompt deleted: id={prompt_id}, user_id={user.id}, name={prompt_name}"
            )

            return JSONResponse(
                status_code=204,
                content=None,
            )
    except Exception as e:
        logger.error(f"Failed to delete prompt {prompt_id}: {e}")
        return JSONResponse(
            status_code=500,
            content={
                "error": "DATABASE_ERROR",
                "message": "An error occurred while deleting.",
            },
        )
