"""Evaluation route handlers."""
from __future__ import annotations

import os
from dataclasses import asdict
from pathlib import Path
from typing import TYPE_CHECKING, Any

from ...schemas import (
    EvaluationScorecardResponse,
    EvaluationRegressionDatasetResponse,
    EvaluationJudgeDisagreementsRequest,
    EvaluationJudgeDisagreementsResponse,
    EvaluationContinuousJobCreateRequest,
    EvaluationContinuousJobsResponse,
    EvaluationContinuousIncidentsResponse,
    EvaluationContinuousTrendDeltaResponse,
    EvaluationContinuousIncidentSnapshotResponse,
    EvaluationContinuousIncidentResponse,
    EvaluationContinuousJobResponse,
    EvaluationContinuousJobRunResponse,
    EvaluationChampionChallengerRequest,
    EvaluationChampionChallengerResponse,
)

if TYPE_CHECKING:
    pass


def _build_eval_quality_manager(continuous_eval_path: str | None) -> Any:
    from logos_adk.quality_history import (
        PostgreSQLQualityHistoryStore,
        QualityExecutionManager,
        SQLiteQualityHistoryStore,
    )

    dsn = os.getenv("LOGOS_ADK_QUALITY_DSN")
    explicit_path = os.getenv("LOGOS_ADK_QUALITY_DB_PATH")
    if dsn:
        return QualityExecutionManager(PostgreSQLQualityHistoryStore(dsn=dsn))

    if explicit_path:
        quality_path = explicit_path
    elif continuous_eval_path:
        quality_path = str(Path(continuous_eval_path).with_name("quality_runs.db"))
    else:
        quality_path = ".logos_adk/quality_runs.db"
    return QualityExecutionManager(SQLiteQualityHistoryStore(path=quality_path))


def _get_eval_engine(learning_store: Any | None) -> Any | None:
    if learning_store is None:
        return None
    from logos_adk.learning import EvaluationLoopEngine

    return EvaluationLoopEngine(learning_store)


def _get_eval_runner(
    learning_store: Any | None,
    *,
    agent: Any | None = None,
    prompt_registry: Any | None = None,
    restore_jobs: bool = True,
) -> Any | None:
    engine = _get_eval_engine(learning_store)
    if engine is None:
        return None

    from logos_adk.learning import ContinuousEvalRunner

    continuous_eval_path = os.getenv("LOGOS_ADK_CONTINUOUS_EVAL_DB_PATH")
    runner = ContinuousEvalRunner(
        engine=engine,
        quality_manager=_build_eval_quality_manager(continuous_eval_path),
        path=continuous_eval_path,
        agent=agent,
        agent_name=getattr(agent, "name", None),
        prompt_registry=prompt_registry,
    )
    if restore_jobs:
        runner.default_agent_name = None
        runner.restore_jobs()
    return runner


def _build_mock_judge(agent: Any, *, mock_response: str, pass_threshold: float) -> Any:
    from logos_adk.providers.mock import MockProvider
    from logos_adk.testing_framework import LLMJudge

    return LLMJudge(
        agent.__class__("judge", model=MockProvider(responses=[mock_response])),
        pass_threshold=pass_threshold,
    )


async def get_scorecard_handler(
    workspace_id: str | None = None,
    agent_name: str | None = None,
    window_days: int = 7,
    learning_store: Any | None = None,
) -> EvaluationScorecardResponse:
    """Handle GET /learning/evaluation/scorecard."""
    engine = _get_eval_engine(learning_store)
    if engine is None:
        return EvaluationScorecardResponse(scorecard={"error": "learning_store not configured"})

    scorecard = engine.build_scorecard(
        workspace_id=workspace_id,
        agent_name=agent_name,
        window_days=window_days,
    )
    return EvaluationScorecardResponse(scorecard=asdict(scorecard))


async def get_regression_dataset_handler(
    workspace_id: str | None = None,
    agent_name: str | None = None,
    limit: int = 100,
    learning_store: Any | None = None,
) -> EvaluationRegressionDatasetResponse:
    """Handle GET /learning/evaluation/regression-dataset."""
    engine = _get_eval_engine(learning_store)
    if engine is None:
        return EvaluationRegressionDatasetResponse(dataset={"error": "learning_store not configured"})

    dataset = engine.build_regression_dataset(
        workspace_id=workspace_id,
        agent_name=agent_name,
        limit=limit,
    )
    return EvaluationRegressionDatasetResponse(dataset=asdict(dataset))


async def get_judge_disagreements_handler(
    request: EvaluationJudgeDisagreementsRequest,
    agent: Any | None = None,
    learning_store: Any | None = None,
) -> EvaluationJudgeDisagreementsResponse:
    """Handle POST /learning/evaluation/judge-disagreements."""
    engine = _get_eval_engine(learning_store)
    if engine is None or agent is None:
        return EvaluationJudgeDisagreementsResponse(
            summary={"error": "learning_store not configured"},
            items=[],
        )

    result = await engine.run_judge_snapshot(
        agent,
        judge=_build_mock_judge(
            agent,
            mock_response=request.mock_response,
            pass_threshold=request.pass_threshold,
        ),
        workspace_id=request.workspace_id,
        agent_name=request.agent_name,
        limit=request.limit,
    )
    return EvaluationJudgeDisagreementsResponse(
        summary=result.get("summary", {}),
        items=result.get("disagreements", []),
    )


async def create_eval_job_handler(
    request: EvaluationContinuousJobCreateRequest,
    agent: Any | None = None,
    prompt_registry: Any | None = None,
    learning_store: Any | None = None,
) -> EvaluationContinuousJobResponse:
    """Handle POST /learning/evaluation/jobs."""
    runner = _get_eval_runner(
        learning_store,
        agent=agent,
        prompt_registry=prompt_registry,
    )
    if runner is None or agent is None:
        return EvaluationContinuousJobResponse(job={"error": "learning_store not configured"})

    existing = runner.get_job(request.name)
    if existing is not None:
        return EvaluationContinuousJobResponse(job=runner.job_snapshot(existing))

    metadata = dict(request.metadata or {})
    if request.kind == "judge-eval":
        metadata.setdefault("judge_kind", "mock")
        metadata.setdefault("mock_response", request.mock_response)
        metadata.setdefault("pass_threshold", request.pass_threshold)
        job = runner.register_judge_job(
            request.name,
            agent=agent,
            judge=_build_mock_judge(
                agent,
                mock_response=request.mock_response,
                pass_threshold=request.pass_threshold,
            ),
            workspace_id=request.workspace_id,
            agent_name=request.agent_name,
            interval_seconds=request.interval_seconds,
            limit=request.limit,
            metadata=metadata,
        )
    else:
        job = runner.register_regression_job(
            request.name,
            agent=agent,
            workspace_id=request.workspace_id,
            agent_name=request.agent_name,
            interval_seconds=request.interval_seconds,
            limit=request.limit,
            metadata=metadata,
        )
    return EvaluationContinuousJobResponse(job=runner.job_snapshot(job))


async def get_eval_jobs_handler(
    workspace_id: str | None = None,
    agent: Any | None = None,
    prompt_registry: Any | None = None,
    learning_store: Any | None = None,
) -> EvaluationContinuousJobsResponse:
    """Handle GET /learning/evaluation/jobs."""
    runner = _get_eval_runner(
        learning_store,
        agent=agent,
        prompt_registry=prompt_registry,
    )
    if runner is None:
        return EvaluationContinuousJobsResponse(items=[])

    items = runner.list_jobs()
    if workspace_id is not None:
        items = [item for item in items if item.get("workspace_id") == workspace_id]
    return EvaluationContinuousJobsResponse(items=items)


async def get_restored_eval_jobs_handler(
    workspace_id: str | None = None,
    agent: Any | None = None,
    prompt_registry: Any | None = None,
    learning_store: Any | None = None,
) -> EvaluationContinuousJobsResponse:
    """Handle GET /learning/evaluation/restored-jobs."""
    runner = _get_eval_runner(
        learning_store,
        agent=agent,
        prompt_registry=prompt_registry,
    )
    if runner is None:
        return EvaluationContinuousJobsResponse(items=[])

    items = runner.list_restored_jobs()
    if workspace_id is not None:
        items = [item for item in items if item.get("workspace_id") == workspace_id]
    return EvaluationContinuousJobsResponse(items=items)


async def get_eval_incidents_handler(
    workspace_id: str | None = None,
    job_name: str | None = None,
    kind: str | None = None,
    status: str | None = None,
    limit: int = 50,
    agent: Any | None = None,
    prompt_registry: Any | None = None,
    learning_store: Any | None = None,
) -> EvaluationContinuousIncidentsResponse:
    """Handle GET /learning/evaluation/incidents."""
    runner = _get_eval_runner(
        learning_store,
        agent=agent,
        prompt_registry=prompt_registry,
    )
    if runner is None:
        return EvaluationContinuousIncidentsResponse(items=[])

    incidents = runner.list_incidents(
        limit=limit,
        kind=kind,
        job_name=job_name,
        workspace_id=workspace_id,
        status=status,
    )
    return EvaluationContinuousIncidentsResponse(items=incidents)


async def get_eval_trend_handler(
    workspace_id: str | None = None,
    job_name: str | None = None,
    window_days: int = 7,
    agent: Any | None = None,
    prompt_registry: Any | None = None,
    learning_store: Any | None = None,
) -> EvaluationContinuousTrendDeltaResponse:
    """Handle GET /learning/evaluation/trend-delta."""
    runner = _get_eval_runner(
        learning_store,
        agent=agent,
        prompt_registry=prompt_registry,
    )
    if runner is None:
        return EvaluationContinuousTrendDeltaResponse(report={"error": "learning_store not configured"})

    report = runner.trend_delta_report(
        workspace_id=workspace_id,
        job_name=job_name,
        window_days=window_days,
    )
    return EvaluationContinuousTrendDeltaResponse(report=asdict(report))


async def get_incident_snapshot_handler(
    incident_id: str | None = None,
    workspace_id: str | None = None,
    job_name: str | None = None,
    status: str | None = None,
    limit: int = 20,
    agent: Any | None = None,
    prompt_registry: Any | None = None,
    learning_store: Any | None = None,
) -> EvaluationContinuousIncidentSnapshotResponse:
    """Handle GET /learning/evaluation/incidents/{incident_id}/snapshot."""
    runner = _get_eval_runner(
        learning_store,
        agent=agent,
        prompt_registry=prompt_registry,
    )
    if runner is None:
        return EvaluationContinuousIncidentSnapshotResponse(snapshot={"error": "learning_store not configured"})

    snapshot = asdict(
        runner.incident_snapshot(
            workspace_id=workspace_id,
            job_name=job_name,
            status=status,
            limit=limit,
        )
    )
    if incident_id is not None:
        snapshot["incident"] = runner.get_incident(incident_id)
    return EvaluationContinuousIncidentSnapshotResponse(snapshot=snapshot)


async def acknowledge_incident_handler(
    incident_id: str,
    actor: str | None = None,
    note: str | None = None,
    agent: Any | None = None,
    prompt_registry: Any | None = None,
    learning_store: Any | None = None,
) -> EvaluationContinuousIncidentResponse:
    """Handle POST /learning/evaluation/incidents/{incident_id}/acknowledge."""
    runner = _get_eval_runner(
        learning_store,
        agent=agent,
        prompt_registry=prompt_registry,
    )
    if runner is None:
        return EvaluationContinuousIncidentResponse(incident={"error": "learning_store not configured"})

    incident = runner.acknowledge_incident(incident_id, actor=actor, note=note)
    return EvaluationContinuousIncidentResponse(
        incident=incident or {"id": incident_id, "error": "incident not found"}
    )


async def resolve_incident_handler(
    incident_id: str,
    actor: str | None = None,
    note: str | None = None,
    agent: Any | None = None,
    prompt_registry: Any | None = None,
    learning_store: Any | None = None,
) -> EvaluationContinuousIncidentResponse:
    """Handle POST /learning/evaluation/incidents/{incident_id}/resolve."""
    runner = _get_eval_runner(
        learning_store,
        agent=agent,
        prompt_registry=prompt_registry,
    )
    if runner is None:
        return EvaluationContinuousIncidentResponse(incident={"error": "learning_store not configured"})

    incident = runner.resolve_incident(incident_id, actor=actor, note=note)
    return EvaluationContinuousIncidentResponse(
        incident=incident or {"id": incident_id, "error": "incident not found"}
    )


async def get_eval_job_handler(
    job_id: str,
    agent: Any | None = None,
    prompt_registry: Any | None = None,
    learning_store: Any | None = None,
) -> EvaluationContinuousJobResponse:
    """Handle GET /learning/evaluation/jobs/{job_id}."""
    runner = _get_eval_runner(
        learning_store,
        agent=agent,
        prompt_registry=prompt_registry,
    )
    if runner is None:
        return EvaluationContinuousJobResponse(job={"error": "learning_store not configured"})

    job = runner.get_job(job_id)
    if job is None:
        return EvaluationContinuousJobResponse(job={"error": "job not found"})
    return EvaluationContinuousJobResponse(job=runner.job_snapshot(job))


async def run_eval_job_handler(
    job_id: str,
    agent: Any | None = None,
    prompt_registry: Any | None = None,
    learning_store: Any | None = None,
) -> EvaluationContinuousJobRunResponse:
    """Handle POST /learning/evaluation/jobs/{job_id}/run."""
    runner = _get_eval_runner(
        learning_store,
        agent=agent,
        prompt_registry=prompt_registry,
    )
    if runner is None:
        return EvaluationContinuousJobRunResponse(
            job={"error": "learning_store not configured"},
            run={},
        )

    if runner.get_job(job_id) is None:
        return EvaluationContinuousJobRunResponse(job={"error": "job not found"}, run={})

    run = await runner.run_job_once(job_id)
    job = runner.get_job(job_id)
    return EvaluationContinuousJobRunResponse(
        job=runner.job_snapshot(job) if job is not None else {"id": job_id},
        run=asdict(run),
    )


async def delete_eval_job_handler(
    job_id: str,
    agent: Any | None = None,
    prompt_registry: Any | None = None,
    learning_store: Any | None = None,
) -> EvaluationContinuousJobResponse:
    """Handle DELETE /learning/evaluation/jobs/{job_id}."""
    runner = _get_eval_runner(
        learning_store,
        agent=agent,
        prompt_registry=prompt_registry,
    )
    if runner is None:
        return EvaluationContinuousJobResponse(job={"error": "learning_store not configured"})

    removed = await runner.remove_job(job_id)
    return EvaluationContinuousJobResponse(job=removed or {"error": "job not found"})


async def champion_challenger_handler(
    request: EvaluationChampionChallengerRequest,
    agent: Any | None = None,
    learning_store: Any | None = None,
) -> EvaluationChampionChallengerResponse:
    """Handle POST /learning/evaluation/champion-challenger."""
    engine = _get_eval_engine(learning_store)
    if engine is None or agent is None:
        return EvaluationChampionChallengerResponse(report={"error": "learning_store not configured"})

    report = await engine.compare_champion_challenger(
        agent,
        challenger_prompt=request.challenger_prompt,
        champion_prompt=request.champion_prompt,
        workspace_id=request.workspace_id,
        agent_name=request.agent_name,
        champion_filter=request.champion_filter,
        challenger_filter=request.challenger_filter,
        limit=request.limit,
        reward_scorer_mode=request.reward_scorer_mode,
        reward_training_limit=request.reward_training_limit,
    )
    return EvaluationChampionChallengerResponse(report=asdict(report))


__all__ = [
    "get_scorecard_handler",
    "get_regression_dataset_handler",
    "get_judge_disagreements_handler",
    "create_eval_job_handler",
    "get_eval_jobs_handler",
    "get_restored_eval_jobs_handler",
    "get_eval_incidents_handler",
    "get_eval_trend_handler",
    "get_incident_snapshot_handler",
    "acknowledge_incident_handler",
    "resolve_incident_handler",
    "get_eval_job_handler",
    "run_eval_job_handler",
    "delete_eval_job_handler",
    "champion_challenger_handler",
]
