# Copyright (c) 2025 Patrick Motsch
# All rights reserved.
from fastapi import APIRouter, HTTPException, Depends, Body, Path, Request, Query
from typing import List, Dict, Any, Optional
from fastapi import status
import logging
import json

# Import auth module
from modules.auth import limiter, getCurrentUser

# Import interfaces
import modules.interfaces.interfaceDbManagement as interfaceDbManagement
from modules.datamodels.datamodelUtils import Prompt
from modules.datamodels.datamodelUam import User
from modules.datamodels.datamodelPagination import PaginationParams, PaginatedResponse, PaginationMetadata, normalize_pagination_dict

# Configure logger
logger = logging.getLogger(__name__)

# Create router for prompt endpoints
router = APIRouter(
    prefix="/api/prompts",
    tags=["Manage Prompts"],
    responses={404: {"description": "Not found"}}
)

@router.get("", response_model=PaginatedResponse[Prompt])
@limiter.limit("30/minute")
def get_prompts(
    request: Request,
    pagination: Optional[str] = Query(None, description="JSON-encoded PaginationParams object"),
    currentUser: User = Depends(getCurrentUser)
) -> PaginatedResponse[Prompt]:
    """
    Get prompts with optional pagination, sorting, and filtering.
    
    Query Parameters:
    - pagination: JSON-encoded PaginationParams object, or None for no pagination
    
    Examples:
    - GET /api/prompts (no pagination - returns all items)
    - GET /api/prompts?pagination={"page":1,"pageSize":10,"sort":[]}
    - GET /api/prompts?pagination={"page":2,"pageSize":20,"sort":[{"field":"name","direction":"asc"}]}
    """
    # Parse pagination parameter
    paginationParams = None
    if pagination:
        try:
            paginationDict = json.loads(pagination)
            if paginationDict:
                # Normalize pagination dict (handles top-level "search" field)
                paginationDict = normalize_pagination_dict(paginationDict)
                paginationParams = PaginationParams(**paginationDict)
        except (json.JSONDecodeError, ValueError) as e:
            raise HTTPException(
                status_code=400,
                detail=f"Invalid pagination parameter: {str(e)}"
            )
    
    managementInterface = interfaceDbManagement.getInterface(currentUser)
    result = managementInterface.getAllPrompts(pagination=paginationParams)
    
    # If pagination was requested, result is PaginatedResult
    # If no pagination, result is List[Prompt]
    if paginationParams:
        return PaginatedResponse(
            items=result.items,
            pagination=PaginationMetadata(
                currentPage=paginationParams.page,
                pageSize=paginationParams.pageSize,
                totalItems=result.totalItems,
                totalPages=result.totalPages,
                sort=paginationParams.sort,
                filters=paginationParams.filters
            )
        )
    else:
        return PaginatedResponse(
            items=result,
            pagination=None
        )

@router.post("", response_model=Prompt)
@limiter.limit("10/minute")
def create_prompt(
    request: Request,
    prompt: Prompt,
    currentUser: User = Depends(getCurrentUser)
) -> Prompt:
    """Create a new prompt"""
    managementInterface = interfaceDbManagement.getInterface(currentUser)
    
    # Create prompt
    newPrompt = managementInterface.createPrompt(prompt)
    
    return Prompt(**newPrompt)

@router.get("/{promptId}", response_model=Prompt)
@limiter.limit("30/minute")
def get_prompt(
    request: Request,
    promptId: str = Path(..., description="ID of the prompt"),
    currentUser: User = Depends(getCurrentUser)
) -> Prompt:
    """Get a specific prompt"""
    managementInterface = interfaceDbManagement.getInterface(currentUser)
    
    # Get prompt
    prompt = managementInterface.getPrompt(promptId)
    if not prompt:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Prompt with ID {promptId} not found"
        )
    
    return prompt

@router.put("/{promptId}", response_model=Prompt)
@limiter.limit("10/minute")
def update_prompt(
    request: Request,
    promptId: str = Path(..., description="ID of the prompt to update"),
    promptData: Dict[str, Any] = Body(...),
    currentUser: User = Depends(getCurrentUser)
) -> Prompt:
    """Update an existing prompt (supports partial updates for inline editing)"""
    managementInterface = interfaceDbManagement.getInterface(currentUser)
    
    # Check if the prompt exists
    existingPrompt = managementInterface.getPrompt(promptId)
    if not existingPrompt:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Prompt with ID {promptId} not found"
        )
    
    # Remove id from update data if present
    update_data = {k: v for k, v in promptData.items() if k != "id"}
    
    # Update prompt (ownership check happens in interface)
    try:
        updatedPrompt = managementInterface.updatePrompt(promptId, update_data)
    except PermissionError as e:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail=str(e)
        )
    
    if not updatedPrompt:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="Error updating the prompt"
        )
    
    return Prompt(**updatedPrompt)

@router.delete("/{promptId}", response_model=Dict[str, Any])
@limiter.limit("10/minute")
def delete_prompt(
    request: Request,
    promptId: str = Path(..., description="ID of the prompt to delete"),
    currentUser: User = Depends(getCurrentUser)
) -> Dict[str, Any]:
    """Delete a prompt"""
    managementInterface = interfaceDbManagement.getInterface(currentUser)
    
    # Check if the prompt exists
    existingPrompt = managementInterface.getPrompt(promptId)
    if not existingPrompt:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Prompt with ID {promptId} not found"
        )
    
    try:
        success = managementInterface.deletePrompt(promptId)
    except PermissionError as e:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail=str(e)
        )
    
    if not success:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="Error deleting the prompt"
        )
    
    return {"message": f"Prompt with ID {promptId} successfully deleted"}