from copy import deepcopy


DEFAULT_POLICY = {
    "weights": {
        "validated": 8.0,
        "injected": 10.0,
        "created": 1.0,
        "rejected": -10.0,
        "task_draft": 2.0,
        "wrapper_draft": 0.5,
        "patch_draft": 0.5,
        "validation_error": -1.0,
        "confidence": 4.0,
    },
    "require_validated": True,
}


def evaluate_candidates(candidates, policy=None):
    policy_obj = _merge_policy(policy)
    ranked = []
    for idx, candidate in enumerate(candidates or []):
        score, breakdown = _score_candidate(candidate, policy_obj)
        ranked.append(
            {
                "rank": 0,
                "proposal_id": str(candidate.get("proposal_id") or f"candidate-{idx}"),
                "score": round(score, 6),
                "status": str(candidate.get("status") or "unknown"),
                "artifact_type": str(((candidate.get("artifact") or {}).get("artifact_type")) or "unknown"),
                "eligible": _is_eligible(candidate, policy_obj),
                "breakdown": breakdown,
            }
        )

    ranked.sort(key=lambda row: (-row["score"], row["proposal_id"]))
    for index, row in enumerate(ranked, start=1):
        row["rank"] = index
    return ranked


def select_winner(ranked_results, require_validated=True):
    ranked = list(ranked_results or [])
    if not ranked:
        return None
    if require_validated:
        for row in ranked:
            if row.get("eligible"):
                return row
        return None
    return ranked[0]


def _score_candidate(candidate, policy_obj):
    weights = policy_obj["weights"]
    score = 0.0
    breakdown = {}

    status = str(candidate.get("status") or "").lower()
    if status in weights:
        score += float(weights[status])
        breakdown[f"status:{status}"] = float(weights[status])

    artifact_type = str(((candidate.get("artifact") or {}).get("artifact_type")) or "").lower()
    if artifact_type in weights:
        score += float(weights[artifact_type])
        breakdown[f"artifact:{artifact_type}"] = float(weights[artifact_type])

    validation = candidate.get("validation") or {}
    errors = validation.get("errors") if isinstance(validation, dict) else []
    error_count = len(errors) if isinstance(errors, list) else 0
    if error_count:
        delta = float(weights.get("validation_error", -1.0)) * float(error_count)
        score += delta
        breakdown["validation:error_count"] = delta

    confidence = _read_confidence(candidate)
    if confidence is not None:
        conf_score = float(weights.get("confidence", 0.0)) * float(confidence)
        score += conf_score
        breakdown["confidence"] = conf_score

    return score, breakdown


def _read_confidence(candidate):
    artifact = candidate.get("artifact") or {}
    body = artifact.get("body") if isinstance(artifact, dict) else {}
    if not isinstance(body, dict):
        return None
    raw = body.get("confidence", artifact.get("confidence"))
    try:
        value = float(raw)
    except (TypeError, ValueError):
        return None
    if value < 0:
        return 0.0
    if value > 1:
        return 1.0
    return value


def _is_eligible(candidate, policy_obj):
    if not policy_obj.get("require_validated", True):
        return True
    status = str(candidate.get("status") or "").lower()
    return status in {"validated", "injected"}


def _merge_policy(policy):
    merged = deepcopy(DEFAULT_POLICY)
    if not isinstance(policy, dict):
        return merged
    if isinstance(policy.get("weights"), dict):
        for key, value in policy["weights"].items():
            try:
                merged["weights"][str(key)] = float(value)
            except (TypeError, ValueError):
                continue
    if "require_validated" in policy:
        merged["require_validated"] = bool(policy.get("require_validated"))
    return merged
