"""Criteria AI API endpoints."""

from __future__ import annotations
from fastapi import APIRouter, Request

from api.utils import classify_and_raise
from api.schemas.criteria import (
    CriteriaGenerateRequest,
    CriteriaGenerateResponse,
    CriterionResponse,
    PICOExtractRequest,
    PICOExtractResponse,
    CriteriaRefineRequest,
    ContextRefineRequest,
    ContextRefineResponse,
    ConsolidateRequest,
    ConsolidateResponse,
    DuplicateGroupResponse,
    ConsolidationProposalResponse,
    QuestionAnalysisRequest,
    QuestionAnalysisResponse,
)

router = APIRouter()


@router.post("/generate", response_model=CriteriaGenerateResponse)
async def generate_criteria(req: CriteriaGenerateRequest, request: Request):
    """Generate inclusion/exclusion criteria from project context."""
    if req.mock:
        from crystallise.screening.mock import MockAIService

        mock = MockAIService()
        raw = mock.generate_exclusion_criteria_from_context(req.project_description, req.research_questions)
        criteria = [
            CriterionResponse(
                category=c.get("criteria_name", "Other"),
                text=c.get("criteria_value", ""),
                description=c.get("rationale", ""),
                criterion_type=c.get("criteria_type", req.criterion_type),
            )
            for c in raw
        ]
        return CriteriaGenerateResponse(criteria=criteria)

    try:
        from crystallise.criteria.ai_service import generate_criteria

        raw = await generate_criteria(
            project_description=req.project_description,
            research_questions=req.research_questions,
            additional_notes=req.additional_notes,
            existing_criteria=req.existing_criteria,
            criterion_type=req.criterion_type,
            model=req.model,
            api_key=request.headers.get("x-openai-api-key"),
        )
        criteria = [
            CriterionResponse(
                category=c.get("category", "Other"),
                text=c.get("text", ""),
                description=c.get("description", ""),
                criterion_type=c.get("criterion_type", req.criterion_type),
                confidence=c.get("confidence"),
                rationale=c.get("rationale"),
            )
            for c in raw
        ]
        return CriteriaGenerateResponse(criteria=criteria)
    except Exception as e:
        classify_and_raise(e)


@router.post("/picos", response_model=PICOExtractResponse)
async def extract_picos(req: PICOExtractRequest, request: Request):
    """Extract PICOS elements (Population, Intervention, Comparator, Outcome, Study Design)."""
    return await _extract_picos_impl(req, request)


@router.post("/pico", response_model=PICOExtractResponse, deprecated=True)
async def extract_pico(req: PICOExtractRequest, request: Request):
    """Extract PICOS elements. Deprecated: use /criteria/picos instead."""
    return await _extract_picos_impl(req, request)


async def _extract_picos_impl(req: PICOExtractRequest, request: Request) -> PICOExtractResponse:
    """Shared implementation for PICOS extraction."""
    if req.mock:
        return PICOExtractResponse(
            elements={
                "population": "Adults with the condition described in the project",
                "intervention": "The primary intervention or exposure under review",
                "comparison": "Standard of care, placebo, or no intervention",
                "outcome": "Primary clinical outcomes, efficacy, and safety measures",
                "study_design": "Study designs relevant to the research question",
            },
            gap_flags=["Mock mode: PICOS elements are placeholders — run without mock for real extraction"],
            contraindications=[],
        )

    try:
        from crystallise.criteria.ai_service import extract_pico

        result = await extract_pico(
            project_description=req.project_description,
            research_questions=req.research_questions,
            model=req.model,
            api_key=request.headers.get("x-openai-api-key"),
        )
        # Normalize LLM response: key may be 'pico_extraction' or 'elements'
        elements = result.get("elements") or result.get("pico_extraction", {})

        # gap_flags may be list of strings or list of dicts
        raw_flags = result.get("gap_flags", [])
        gap_flags: list[str] = []
        for f in raw_flags:
            if isinstance(f, str):
                gap_flags.append(f)
            elif isinstance(f, dict):
                parts = [f.get("element", ""), f.get("suggestion", f.get("description", ""))]
                gap_flags.append(": ".join(p for p in parts if p))

        contraindications = result.get("contraindications", [])

        return PICOExtractResponse(
            elements=elements,
            gap_flags=gap_flags,
            contraindications=contraindications,
        )
    except Exception as e:
        classify_and_raise(e)


@router.post("/refine-context", response_model=ContextRefineResponse)
async def refine_context(req: ContextRefineRequest, request: Request):
    """Refine project description and research questions for better AI screening."""
    if req.mock:
        return ContextRefineResponse(
            refined_description=req.description
            + "\n\n[Refined for clarity and specificity in systematic review screening.]",
            refined_research_questions=[f"{rq} [refined for precision]" for rq in req.research_questions]
            if req.research_questions
            else ["What is the effectiveness of the intervention in the target population? [mock]"],
            explanation="Mock mode: minor refinements applied as placeholders. Run without mock for real AI refinement.",
        )

    try:
        from crystallise.criteria.ai_service import refine_context as ai_refine_context

        result = await ai_refine_context(
            description=req.description,
            research_questions=req.research_questions,
            model=req.model,
            api_key=request.headers.get("x-openai-api-key"),
        )
        return ContextRefineResponse(
            refined_description=result.get("refined_description", req.description),
            refined_research_questions=result.get("refined_research_questions", req.research_questions),
            explanation=result.get("explanation", ""),
        )
    except Exception as e:
        classify_and_raise(e)


@router.post("/refine", response_model=CriteriaGenerateResponse)
async def refine_criteria(req: CriteriaRefineRequest, request: Request):
    """Refine criteria based on conflicts and context."""
    if req.mock:
        from crystallise.screening.mock import MockAIService

        mock = MockAIService()
        raw = mock.generate_from_conflicts(req.conflicts)
        criteria = [
            CriterionResponse(
                category=c.get("category", "Other"),
                text=c.get("text", ""),
                description=c.get("description", ""),
                criterion_type=c.get("criterion_type", "exclude"),
                confidence=c.get("confidence"),
                rationale=c.get("rationale"),
            )
            for c in raw
        ]
        return CriteriaGenerateResponse(criteria=criteria)

    try:
        from crystallise.criteria.ai_service import refine_criteria

        raw = await refine_criteria(
            current_criteria=req.current_criteria,
            conflicts=req.conflicts,
            project_description=req.project_description,
            model=req.model,
            api_key=request.headers.get("x-openai-api-key"),
        )
        criteria = [
            CriterionResponse(
                category=c.get("category", "Other"),
                text=c.get("text", ""),
                description=c.get("description", ""),
                criterion_type=c.get("criterion_type", "exclude"),
                confidence=c.get("confidence"),
                rationale=c.get("rationale"),
            )
            for c in raw
        ]
        return CriteriaGenerateResponse(criteria=criteria)
    except Exception as e:
        classify_and_raise(e)


@router.post("/consolidate", response_model=ConsolidateResponse)
async def consolidate_criteria_endpoint(req: ConsolidateRequest, request: Request):
    """Detect duplicate and overlapping criteria, propose consolidations."""
    if req.mock:
        return ConsolidateResponse(
            duplicate_groups=[],
            consolidation_proposals=[],
            warnings=["Mock mode: no consolidation performed"],
        )

    try:
        from crystallise.criteria.ai_service import consolidate_criteria as ai_consolidate
        from crystallise.criteria.models import ExclusionCriterion

        criteria_objs = [
            ExclusionCriterion(
                id=c.get("id", i),
                project_id=c.get("project_id", 0),
                category=c.get("category", "Other"),
                text=c.get("text", ""),
                description=c.get("description", ""),
                criterion_type=c.get("criterion_type", "exclude"),
                is_active=c.get("is_active", True),
                source=c.get("source", "human"),
            )
            for i, c in enumerate(req.criteria)
        ]

        result = await ai_consolidate(
            criteria=criteria_objs,
            project_description=req.project_description,
            research_questions=req.research_questions,
            model=req.model,
            api_key=request.headers.get("x-openai-api-key"),
        )

        return ConsolidateResponse(
            duplicate_groups=[
                DuplicateGroupResponse(**g.model_dump() if hasattr(g, "model_dump") else g.__dict__)
                for g in result.duplicate_groups
            ],
            consolidation_proposals=[
                ConsolidationProposalResponse(**p.model_dump() if hasattr(p, "model_dump") else p.__dict__)
                for p in result.consolidation_proposals
            ],
            warnings=result.warnings,
        )
    except Exception as e:
        classify_and_raise(e)


@router.post("/analyze-question", response_model=QuestionAnalysisResponse)
async def analyze_question(req: QuestionAnalysisRequest, request: Request):
    """Analyse a single research question for systematic-review search readiness (PICOS)."""
    if req.mock:
        return QuestionAnalysisResponse(
            status="could_improve",
            missing_elements=[
                "Population is not specified",
                "Outcome measures are vague",
            ],
            suggestion=(
                "Mock mode: specify the population, intervention, and primary outcome "
                "to make the question searchable. Run without mock for real analysis."
            ),
        )

    try:
        from crystallise.criteria.ai_service import analyze_research_question

        result = await analyze_research_question(
            research_question=req.research_question,
            model=req.model,
            api_key=request.headers.get("x-openai-api-key"),
        )
        return QuestionAnalysisResponse(
            status=result.get("status", "could_improve"),
            missing_elements=result.get("missing_elements", []),
            suggestion=result.get("suggestion", ""),
        )
    except Exception as e:
        classify_and_raise(e)
