"""
Score normalization utilities for consistent 0-1 range handling.
"""

from typing import Union, Optional, List, Dict, Any
import math


def norm01(x: Union[float, int, str, None]) -> float:
    """
    Normalize score to 0-1 range with safe handling.

    Args:
        x: Score value (can be 0-1 or 0-100 scale, or string)

    Returns:
        Float in [0.0, 1.0] range
    """
    try:
        if x is None:
            return 0.0

        # Handle strings with percent sign (e.g., "85%")
        s = str(x).strip()
        if s.endswith("%"):
            try:
                return max(0.0, min(1.0, float(s[:-1]) / 100.0))
            except:
                return 0.0

        x = float(x)

        # Handle NaN values
        if math.isnan(x):
            return 0.0

        # If >= 2 and <= 100, assume it's 0-100 scale
        # This handles integer percentages while allowing 1.0-2.0 to be clamped
        if x >= 2 and x <= 100:
            x = x / 100.0

        # Clamp to [0, 1] (handles values > 100 or between 1-2)
        return max(0.0, min(1.0, x))
    except (ValueError, TypeError):
        return 0.0


def normalize_field_scores(
    field_score_details: Union[List[Dict], str, None],
) -> List[Dict[str, Any]]:
    """
    Normalize all scores in field_score_details to 0-1 range.

    Args:
        field_score_details: List of field score dicts or JSON string

    Returns:
        List of dicts with normalized scores
    """
    if not field_score_details:
        return []

    # Parse if string
    if isinstance(field_score_details, str):
        try:
            import json

            field_score_details = json.loads(field_score_details)
        except:
            return []

    if not isinstance(field_score_details, list):
        return []

    # Normalize each detail
    normalized = []
    for detail in field_score_details:
        if isinstance(detail, dict):
            detail_copy = detail.copy()
            if "score" in detail_copy:
                detail_copy["score"] = norm01(detail_copy["score"])
            if "confidence" in detail_copy:
                detail_copy["confidence"] = norm01(detail_copy["confidence"])
            if "similarity" in detail_copy:
                detail_copy["similarity"] = norm01(detail_copy["similarity"])
            normalized.append(detail_copy)

    return normalized


def normalize_suggestion(suggestion: Dict[str, Any]) -> Dict[str, Any]:
    """
    Normalize all scores in a suggestion to 0-1 range.

    Args:
        suggestion: Suggestion dict with score fields

    Returns:
        Suggestion dict with normalized scores
    """
    result = suggestion.copy()

    # Main score
    if "score" in result:
        result["score"] = norm01(result["score"])

    # Evidence strength
    if "evidence_strength" in result:
        result["evidence_strength"] = norm01(result["evidence_strength"])

    # Field score details
    if "field_score_details" in result:
        result["field_score_details"] = normalize_field_scores(
            result["field_score_details"]
        )

    # For dedupe: incumbent_score, gain
    if "incumbent_score" in result:
        result["incumbent_score"] = norm01(result["incumbent_score"])

    # For merge candidates
    if "candidates" in result and isinstance(result["candidates"], list):
        for candidate in result["candidates"]:
            if isinstance(candidate, dict) and "score" in candidate:
                candidate["score"] = norm01(candidate["score"])

    return result


def get_confidence_tier(
    score: float, thresholds: Optional[Dict[str, float]] = None
) -> str:
    """
    Get confidence tier from normalized score.

    Args:
        score: Normalized score (0-1)
        thresholds: Optional custom thresholds dict

    Returns:
        Tier string (CERTAIN, LIKELY, POSSIBLE, REVIEW, UNLIKELY)
    """
    score = norm01(score)

    if thresholds:
        # Use custom thresholds if provided
        if score >= thresholds.get("certain", 0.90):
            return "CERTAIN"
        elif score >= thresholds.get("likely", 0.75):
            return "LIKELY"
        elif score >= thresholds.get("possible", 0.50):
            return "POSSIBLE"
        elif score >= thresholds.get("review", 0.30):
            return "REVIEW"
        else:
            return "UNLIKELY"
    else:
        # Default thresholds
        if score >= 0.90:
            return "CERTAIN"
        elif score >= 0.75:
            return "LIKELY"
        elif score >= 0.50:
            return "POSSIBLE"
        elif score >= 0.30:
            return "REVIEW"
        else:
            return "UNLIKELY"
