from fastapi import APIRouter, HTTPException, status
from fastapi.responses import FileResponse
from pydantic import BaseModel, Field, HttpUrl
from typing import Optional, Dict, Any, Literal
from datetime import datetime as dt
import os

from pif_compiler.functions.common_func import generate_pdf
from pif_compiler.services.srv_pubchem import pubchem_dap
from pif_compiler.services.srv_cir import search_ingredient
from pif_compiler.functions.common_log import get_logger
from pif_compiler.functions.db_utils import db_connect

logger = get_logger()

router = APIRouter()


class GeneratePdfRequest(BaseModel):
    link: str = Field(..., description="URL of the page to convert to PDF")
    name: str = Field(..., description="Name for the generated PDF file (without extension)")

    class Config:
        json_schema_extra = {
            "example": {
                "link": "https://example.com/page",
                "name": "my_document"
            }
        }


class GeneratePdfResponse(BaseModel):
    success: bool
    name: str
    message: str
    file_path: Optional[str] = None


@router.post("/common/generate-pdf", response_model=GeneratePdfResponse, tags=["Common"])
async def generate_pdf_endpoint(request: GeneratePdfRequest):
    """
    Generate a PDF from a web page URL.

    This endpoint uses Playwright to:
    1. Navigate to the provided URL
    2. Render the page
    3. Generate a PDF file
    4. Save it in the 'pdfs/' directory

    If a PDF with the same name already exists, it will skip generation
    and return success immediately.

    Args:
        request: GeneratePdfRequest with the URL and desired PDF name

    Returns:
        GeneratePdfResponse with success status and file information
    """
    logger.info(f"API request received to generate PDF: name='{request.name}', link='{request.link}'")

    try:
        result = await generate_pdf(request.link, request.name)

        if result:
            file_path = f"pdfs/{request.name}.pdf"

            # Check if file was already existing or newly created
            if os.path.exists(file_path):
                logger.info(f"PDF available for '{request.name}'")
                return GeneratePdfResponse(
                    success=True,
                    name=request.name,
                    message=f"PDF generated successfully or already exists",
                    file_path=file_path
                )
            else:
                logger.error(f"PDF file not found after generation for '{request.name}'")
                return GeneratePdfResponse(
                    success=False,
                    name=request.name,
                    message="PDF generation completed but file not found",
                    file_path=None
                )
        else:
            logger.error(f"PDF generation failed for '{request.name}'")
            return GeneratePdfResponse(
                success=False,
                name=request.name,
                message="PDF generation failed",
                file_path=None
            )

    except Exception as e:
        logger.error(f"Error generating PDF for '{request.name}': {str(e)}", exc_info=True)
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Internal error while generating PDF: {str(e)}"
        )


@router.get("/common/download-pdf/{name}", response_class=FileResponse, tags=["Common"])
async def download_pdf(name: str):
    """
    Download a previously generated PDF file.

    Args:
        name: Name of the PDF file (without extension)

    Returns:
        FileResponse with the PDF file for download
    """
    logger.info(f"API request received to download PDF: name='{name}'")

    file_path = f"pdfs/{name}.pdf"

    if not os.path.exists(file_path):
        logger.warning(f"PDF file not found: {file_path}")
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"PDF file '{name}' not found. Please generate it first using /common/generate-pdf"
        )

    logger.info(f"Serving PDF file: {file_path}")
    return FileResponse(
        path=file_path,
        media_type="application/pdf",
        filename=f"{name}.pdf"
    )


class PubchemRequest(BaseModel):
    cas: str = Field(..., description="CAS number of the substance to search for in PubChem")

    class Config:
        json_schema_extra = {
            "example": {
                "cas": "64-17-5"
            }
        }


class PubchemResponse(BaseModel):
    success: bool
    cas: str
    data: Optional[Dict[str, Any]] = None
    error: Optional[str] = None


@router.post("/common/pubchem", response_model=PubchemResponse, tags=["Common"])
async def search_pubchem(request: PubchemRequest):
    """
    Search for substance information in PubChem database.

    This endpoint retrieves comprehensive substance data from PubChem including:
    - **Basic info**: CID, CAS, first PubChem name, PubChem link
    - **First level properties**: XLogP, molecular weight, TPSA, exact mass
    - **Second level properties**: Melting Point, Dissociation Constants, pH

    The data is automatically cleaned and formatted for easier consumption.

    Args:
        request: PubchemRequest containing the CAS number

    Returns:
        PubchemResponse with the substance data or error information
    """
    logger.info(f"API request received for PubChem search: CAS={request.cas}")

    try:
        result = pubchem_dap(request.cas)

        # Check if result is None (error occurred)
        if result is None:
            logger.error(f"PubChem search returned None for CAS: {request.cas}")
            return PubchemResponse(
                success=False,
                cas=request.cas,
                data=None,
                error="An error occurred while searching PubChem. Please check the logs for details."
            )

        # Check if result is a string (no results found)
        if isinstance(result, str):
            logger.warning(f"No results found in PubChem for CAS: {request.cas}")
            return PubchemResponse(
                success=False,
                cas=request.cas,
                data=None,
                error=result
            )

        # Successful result
        logger.info(f"Successfully retrieved PubChem data for CAS: {request.cas}")
        return PubchemResponse(
            success=True,
            cas=request.cas,
            data=result,
            error=None
        )

    except Exception as e:
        logger.error(f"Error processing PubChem request for CAS {request.cas}: {str(e)}", exc_info=True)
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Internal error while processing PubChem request: {str(e)}"
        )


class CirSearchRequest(BaseModel):
    text: str = Field(..., description="Text to search for in the CIR database")

    class Config:
        json_schema_extra = {
            "example": {
                "text": "olio di argan"
            }
        }


class CirSearchResponse(BaseModel):
    success: bool
    text: str
    results: Optional[list] = None
    count: Optional[int] = None
    error: Optional[str] = None


@router.post("/common/cir-search", response_model=CirSearchResponse, tags=["Common"])
async def cir_search_endpoint(request: CirSearchRequest):
    """
    Search for ingredients in the CIR (Cosmetic Ingredient Review) database.

    This endpoint searches the CIR NOAEL database for ingredients matching
    the provided text query.

    Args:
        request: CirSearchRequest containing the search text

    Returns:
        CirSearchResponse with the search results or error information
    """
    logger.info(f"API request received for CIR search: text='{request.text}'")

    try:
        results = search_ingredient(request.text)

        if results is None:
            logger.error(f"CIR search returned None for text: {request.text}")
            return CirSearchResponse(
                success=False,
                text=request.text,
                results=None,
                count=0,
                error="An error occurred while searching the CIR database. Please check the logs for details."
            )

        logger.info(f"Successfully retrieved {len(results)} results from CIR database for text: {request.text}")
        return CirSearchResponse(
            success=True,
            text=request.text,
            results=results,
            count=len(results),
            error=None
        )

    except Exception as e:
        logger.error(f"Error processing CIR search 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 CIR search request: {str(e)}"
        )


class SegnalazioneRequest(BaseModel):
    cas: Optional[str] = None
    page: str
    description: str
    error: Optional[str] = None
    priority: Literal["bassa", "media", "alta"] = "media"


@router.post("/common/segnalazione", tags=["Common"])
async def create_segnalazione(request: SegnalazioneRequest):
    """Salva una segnalazione/ticket nella collection MongoDB 'segnalazioni'."""
    collection = db_connect(collection_name="segnalazioni")
    if collection is None:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="Connessione MongoDB fallita"
        )

    doc = {
        **request.model_dump(),
        "created_at": dt.now().isoformat(),
        "stato": "aperta",
    }

    try:
        result = collection.insert_one(doc)
        logger.info(f"Segnalazione creata: id={result.inserted_id}, page={request.page}, priority={request.priority}")
        return {"success": True, "id": str(result.inserted_id)}
    except Exception as e:
        logger.error(f"create_segnalazione: errore MongoDB — {e}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="Errore nel salvataggio della segnalazione"
        )


@router.get("/common/health", tags=["Common"])
async def common_health_check():
    """
    Health check endpoint for common functions service.

    Returns the status of the common functions components.
    """
    return {
        "status": "healthy",
        "service": "common-functions",
        "components": {
            "api": "operational",
            "logging": "operational",
            "utilities": "operational",
            "pubchem": "operational",
            "cir": "operational"
        }
    }



