from fastapi import APIRouter, HTTPException, status
from pydantic import BaseModel, Field
from typing import Optional, Dict, Any, List, Literal

from pif_compiler.services.srv_cosing import cosing_search, clean_cosing
from pif_compiler.functions.common_log import get_logger

logger = get_logger()

router = APIRouter()


class CosingSearchRequest(BaseModel):
    text: str = Field(..., description="Text to search for (name, CAS, EC, or substance ID)")
    mode: Literal["name", "cas", "ec", "id"] = Field(
        default="name",
        description="Search mode: 'name' for INCI/chemical names, 'cas' for CAS numbers, 'ec' for EC numbers, 'id' for substance ID"
    )
    full: bool = Field(
        default=True,
        description="If True, includes identified ingredients in the response"
    )

    class Config:
        json_schema_extra = {
            "example": {
                "text": "Water",
                "mode": "name",
                "full": True
            }
        }


class CosingSearchResponse(BaseModel):
    success: bool
    query: str
    mode: str
    data: Optional[Dict[str, Any]] = None
    error: Optional[str] = None


class CosingBatchRequest(BaseModel):
    searches: List[Dict[str, Any]] = Field(
        ...,
        description="List of search queries, each with 'text' and optionally 'mode' and 'full'"
    )

    class Config:
        json_schema_extra = {
            "example": {
                "searches": [
                    {"text": "Water", "mode": "name"},
                    {"text": "7732-18-5", "mode": "cas"},
                    {"text": "231-791-2", "mode": "ec"}
                ]
            }
        }


class CosingBatchResponse(BaseModel):
    success: bool
    total: int
    successful: int
    failed: int
    results: List[CosingSearchResponse]


@router.post("/cosing/search", response_model=CosingSearchResponse, tags=["COSING"])
async def search_cosing_substance(request: CosingSearchRequest):
    """
    Search for substance information in COSING database.

    This endpoint allows searching the COSING database using different search modes:
    - **name**: Search by INCI name, chemical name, INN name, Ph.Eur name, etc.
    - **cas**: Search by CAS number
    - **ec**: Search by EC number
    - **id**: Search by substance ID

    The response is automatically cleaned and formatted for easier consumption.
    If `full=True`, identified ingredients are recursively fetched and included.

    Args:
        request: CosingSearchRequest with search text, mode, and full flag

    Returns:
        CosingSearchResponse with the cleaned substance data or error information
    """
    logger.info(f"API request received for COSING search: text='{request.text}', mode='{request.mode}', full={request.full}")

    try:
        # Execute the search
        result = cosing_search(request.text, request.mode)

        if result is None:
            logger.warning(f"No data found for text='{request.text}', mode='{request.mode}'")
            return CosingSearchResponse(
                success=False,
                query=request.text,
                mode=request.mode,
                data=None,
                error=f"No data found for the provided search query. The {request.mode} may be invalid or not found in COSING."
            )

        # Clean the result
        cleaned_result = clean_cosing(result, full=request.full)

        logger.info(f"Successfully retrieved and cleaned data for text='{request.text}', mode='{request.mode}'")
        return CosingSearchResponse(
            success=True,
            query=request.text,
            mode=request.mode,
            data=cleaned_result,
            error=None
        )

    except ValueError as e:
        logger.error(f"Validation error for request: {str(e)}")
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=str(e)
        )
    except Exception as e:
        logger.error(f"Error processing COSING request for text='{request.text}': {str(e)}", exc_info=True)
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Internal error while processing COSING search: {str(e)}"
        )


@router.post("/cosing/batch-search", response_model=CosingBatchResponse, tags=["COSING"])
async def batch_search_cosing_substances(request: CosingBatchRequest):
    """
    Search for multiple substances in COSING database.

    This endpoint processes multiple search queries in a single request.
    Each search can have its own mode (name, cas, ec, id) and full flag.

    Args:
        request: CosingBatchRequest containing a list of search queries

    Returns:
        CosingBatchResponse with results for all searches, including
        success/failure counts and individual results
    """
    logger.info(f"Batch API request received for {len(request.searches)} COSING searches")

    results = []
    successful = 0
    failed = 0

    for search_item in request.searches:
        text = search_item.get("text")
        mode = search_item.get("mode", "name")
        full = search_item.get("full", True)

        if not text:
            logger.warning("Batch item missing 'text' field, skipping")
            results.append(CosingSearchResponse(
                success=False,
                query="",
                mode=mode,
                data=None,
                error="Missing 'text' field in search item"
            ))
            failed += 1
            continue

        try:
            logger.info(f"Processing COSING search: text='{text}', mode='{mode}'")
            result = cosing_search(text, mode)

            if result is None:
                logger.warning(f"No data found for text='{text}', mode='{mode}'")
                results.append(CosingSearchResponse(
                    success=False,
                    query=text,
                    mode=mode,
                    data=None,
                    error=f"No data found for the provided search query."
                ))
                failed += 1
            else:
                # Clean the result
                cleaned_result = clean_cosing(result, full=full)

                logger.info(f"Successfully retrieved data for text='{text}', mode='{mode}'")
                results.append(CosingSearchResponse(
                    success=True,
                    query=text,
                    mode=mode,
                    data=cleaned_result,
                    error=None
                ))
                successful += 1

        except ValueError as e:
            logger.error(f"Validation error for text='{text}': {str(e)}")
            results.append(CosingSearchResponse(
                success=False,
                query=text,
                mode=mode,
                data=None,
                error=f"Validation error: {str(e)}"
            ))
            failed += 1
        except Exception as e:
            logger.error(f"Error processing text '{text}': {str(e)}", exc_info=True)
            results.append(CosingSearchResponse(
                success=False,
                query=text,
                mode=mode,
                data=None,
                error=f"Internal error: {str(e)}"
            ))
            failed += 1

    logger.info(f"Batch request completed: {successful} successful, {failed} failed out of {len(request.searches)} total")

    return CosingBatchResponse(
        success=True,
        total=len(request.searches),
        successful=successful,
        failed=failed,
        results=results
    )


@router.get("/cosing/health", tags=["COSING"])
async def cosing_health_check():
    """
    Health check endpoint for COSING service.

    Returns the status of the COSING service components.
    """
    return {
        "status": "healthy",
        "service": "cosing-search",
        "components": {
            "api": "operational",
            "search": "operational",
            "parser": "operational"
        }
    }
