# grantflow/core/strategies/afd.py

from __future__ import annotations

from typing import Type

from pydantic import BaseModel, Field

from grantflow.core.donor_strategy import DonorStrategy


class AFD_Effect(BaseModel):
    effect_id: str = Field(description="Effect identifier (e.g. Effet 1)")
    title: str = Field(description="Effect title")
    description: str = Field(description="Expected development change at outcome level")
    outputs_contributing: list[str] = Field(default_factory=list, description="Output IDs contributing to this effect")


class AFD_Output(BaseModel):
    output_id: str = Field(description="Output identifier (e.g. Produit 1)")
    title: str = Field(description="Output title")
    description: str = Field(description="Deliverable produced by project activities")
    activities: list[str] = Field(default_factory=list, description="Key activities under this output")


class AFD_TOC(BaseModel):
    overall_objective: str = Field(
        description=(
            "Objectif général / Overall objective: the high-level development goal "
            "the project contributes to, beyond direct accountability"
        )
    )
    specific_objective: str = Field(
        description=(
            "Objectif spécifique / Specific objective: the change the project is " "directly accountable for producing"
        )
    )
    outputs: list[AFD_Output] = Field(default_factory=list)
    effects: list[AFD_Effect] = Field(default_factory=list)
    assumptions: list[str] = Field(
        default_factory=list,
        description="Key assumptions (hypothèses) at output and outcome level",
    )
    risks: list[str] = Field(default_factory=list, description="Key risks (risques) and mitigation")
    climate_environment_nexus: str = Field(
        description=(
            "How the project addresses climate and environment considerations. "
            "AFD applies a mandatory climate co-benefit screen."
        )
    )
    gender_social_inclusion: str = Field(description="Gender equality and social inclusion rationale and approach")
    french_expertise_partnership: str = Field(
        description=(
            "Role of French expertise, technical assistance, or institutional partnership. "
            "AFD projects often involve French public institutions or expertise."
        )
    )


class AFD_MELIndicator(BaseModel):
    indicator_id: str = Field(description="Indicator identifier")
    name: str = Field(description="Indicator title")
    logframe_level: str = Field(description="Cadre logique level: Overall Objective / Specific Objective / Output")
    climate_marker: str | None = Field(
        default=None,
        description="AFD climate co-benefit marker: principal / significant / not targeted",
    )
    gender_marker: str | None = Field(
        default=None, description="AFD gender marker: principal / significant / not targeted"
    )
    means_of_verification: str = Field(description="Data source and collection method")
    justification: str = Field(description="Why this indicator captures the intended change")
    citation: str = Field(description="Source reference from AFD guidance corpus")
    baseline: str = Field(description="Baseline value")
    target: str = Field(description="Target value at project end")
    evidence_excerpt: str | None = Field(default=None, description="Optional grounded excerpt")


class AFD_MELDraft(BaseModel):
    indicators: list[AFD_MELIndicator] = Field(default_factory=list)


class AFDStrategy(DonorStrategy):
    donor_id: str = "AFD"

    def get_toc_schema(self) -> Type[AFD_TOC]:
        return AFD_TOC

    def get_rag_collection(self) -> str:
        return "afd_guidance"

    def get_mel_schema(self) -> Type[AFD_MELDraft]:
        return AFD_MELDraft

    def get_system_prompts(self) -> dict:
        return {
            "Architect": (
                "You are an AFD (Agence Française de Développement) proposal architect. "
                "Structure the Theory of Change using AFD cadre logique conventions: "
                "Overall Objective → Specific Objective → Outputs (Produits) → Activities. "
                "AFD requires mandatory climate co-benefit screening — classify the project's "
                "climate contribution as principal, significant, or not targeted, and justify. "
                "Address gender equality and social inclusion explicitly. "
                "Where applicable, identify the role of French public expertise or institutional partnership. "
                "State assumptions (hypothèses) at each level and identify key risks with mitigation."
            ),
            "MEL_Specialist": (
                "You are an AFD results and monitoring specialist. Use only the 'afd_guidance' RAG namespace. "
                "Draft indicators aligned to the cadre logique (Overall Objective / Specific Objective / Output). "
                "For each indicator assign AFD climate and gender markers "
                "(principal / significant / not targeted) and specify means of verification. "
                "Cite AFD evaluation framework, sectoral guidelines, or cadre logique standards."
            ),
            "Red_Team_Critic": (
                "You are a strict AFD reviewer. Apply the following checks: "
                "(1) Cadre logique coherence — do outputs contribute plausibly to the specific objective? "
                "(2) Climate co-benefit — is the marker justified with concrete evidence? "
                "(3) Gender and inclusion — are commitments specific and measurable? "
                "(4) French partnership — is the added value of French expertise clear where claimed? "
                "(5) Assumptions — are they explicit and testable at each level? "
                "Penalise vague climate claims, unsubstantiated gender commitments, "
                "and missing means of verification."
            ),
        }
