"""
Belief Revision System - Evaluator

Orchestrates proposal evaluation using domain-specific smoke tests.
Integrates with the domain registry for test selection.
"""
from __future__ import annotations

import json
from dataclasses import dataclass
from typing import Callable, Dict, List, Optional, Tuple

from .storage import CASStore
from .core import estimate_maturity
from .revision import EvalResult, shadow_import_analog
from .domains import registry


# Re-export SmokeTestResult for convenience
SmokeTestResult = Tuple[int, int, List[str]]


@dataclass
class EvaluationConfig:
    """Configuration for proposal evaluation."""
    base_world: str = "green"
    shadow_prefix: str = "_shadow_eval"
    acceptance_threshold: float = 0.0
    smoke_level: str = "smoke"


def evaluate_with_registry(
    store: CASStore,
    proposal_id: str,
    target_domain: str,
    config: Optional[EvaluationConfig] = None
) -> EvalResult:
    """
    Evaluate a proposal using registry-based smoke tests.

    Args:
        store: Storage backend
        proposal_id: Proposal to evaluate
        target_domain: Domain to test in
        config: Evaluation configuration

    Returns:
        EvalResult with outcome
    """
    if config is None:
        config = EvaluationConfig()

    # Get smoke test from registry
    smoke_fn = registry.get(target_domain, level=config.smoke_level)

    if smoke_fn:
        def smoke_test(st: CASStore, did: str, wl: str) -> Tuple[int, int, List[str]]:
            return smoke_fn(st, did, wl)
    else:
        smoke_test = None  # type: ignore

    # Delegate to revision.evaluate_proposal
    from .revision import evaluate_proposal
    return evaluate_proposal(
        store,
        proposal_id=proposal_id,
        target_domain=target_domain,
        base_world=config.base_world,
        shadow_world=f"{config.shadow_prefix}_{proposal_id[:8]}",
        smoke_test=smoke_test,
        acceptance_threshold=config.acceptance_threshold
    )


def evaluate_all_new(
    store: CASStore,
    target_domain: str,
    config: Optional[EvaluationConfig] = None,
    limit: int = 50
) -> List[EvalResult]:
    """
    Evaluate all new proposals for a domain.

    Args:
        store: Storage backend
        target_domain: Domain to test in
        config: Evaluation configuration
        limit: Maximum proposals to evaluate

    Returns:
        List of EvalResults
    """
    proposals = store.list_proposals(status="new", limit=limit)
    results: List[EvalResult] = []

    for prop in proposals:
        # Check if proposal involves target domain
        try:
            obj = store.get_object(prop["hash"])["json"]
            if target_domain not in (obj.get("left_domain"), obj.get("right_domain")):
                continue
        except KeyError:
            continue

        result = evaluate_with_registry(store, prop["proposal_id"], target_domain, config)
        results.append(result)

    return results


def run_smoke_tests(
    store: CASStore,
    domain_id: str,
    world_label: str = "green",
    level: str = "smoke"
) -> SmokeTestResult:
    """
    Run smoke tests for a domain.

    Args:
        store: Storage backend
        domain_id: Domain to test
        world_label: World version to test
        level: Test level ("smoke", "regression", "deep")

    Returns:
        (tests_run, failures, messages)
    """
    smoke_fn = registry.get(domain_id, level=level)
    if smoke_fn is None:
        return (0, 0, [f"No smoke tests registered for {domain_id}:{level}"])

    return smoke_fn(store, domain_id, world_label)


def available_tests() -> Dict[str, List[str]]:
    """Get all available domain tests and their levels."""
    return registry.summary()


# =============================================================================
# Batch Evaluation
# =============================================================================

def evaluate_proposals_batch(
    store: CASStore,
    proposal_ids: List[str],
    target_domain: str,
    config: Optional[EvaluationConfig] = None
) -> List[EvalResult]:
    """
    Evaluate a batch of proposals.

    Args:
        store: Storage backend
        proposal_ids: Proposals to evaluate
        target_domain: Domain to test in
        config: Evaluation configuration

    Returns:
        List of EvalResults
    """
    results: List[EvalResult] = []
    for pid in proposal_ids:
        result = evaluate_with_registry(store, pid, target_domain, config)
        results.append(result)
    return results


def get_evaluation_summary(results: List[EvalResult]) -> Dict[str, any]:
    """
    Summarize a batch of evaluation results.

    Args:
        results: List of EvalResults

    Returns:
        Summary statistics
    """
    if not results:
        return {"total": 0}

    accepted = sum(1 for r in results if r.outcome == "accepted")
    rejected = sum(1 for r in results if r.outcome == "rejected")
    errors = sum(1 for r in results if r.outcome == "error")
    total_tests = sum(r.tests_run for r in results)
    total_failures = sum(r.failures for r in results)

    deltas = [r.delta for r in results if r.outcome != "error"]
    avg_delta = sum(deltas) / len(deltas) if deltas else 0.0

    return {
        "total": len(results),
        "accepted": accepted,
        "rejected": rejected,
        "errors": errors,
        "acceptance_rate": accepted / len(results) if results else 0.0,
        "total_tests": total_tests,
        "total_failures": total_failures,
        "average_delta": avg_delta,
    }
