"""
Linux BenchTools - Scoring Utilities

Raw benchmark scoring (no normalization):
- CPU: events_per_second (raw)
- Memory: throughput_mib_s (raw)
- Disk: read_mb_s + write_mb_s (raw)
- Network: upload_mbps + download_mbps (raw)
- GPU: glmark2_score (raw)
"""

from app.core.config import settings


def calculate_cpu_score(events_per_second: float = None) -> float:
    """
    Calculate CPU score from sysbench events per second.

    Formula: events_per_second (raw value)
    No normalization applied.

    Example: 3409.87 events/s → 3409.87 score
    """
    if events_per_second is None or events_per_second <= 0:
        return 0.0

    return max(0.0, events_per_second)


def calculate_memory_score(throughput_mib_s: float = None) -> float:
    """
    Calculate Memory score from sysbench throughput.

    Formula: throughput_mib_s (raw value)
    No normalization applied.

    Example: 13806.03 MiB/s → 13806.03 score
    """
    if throughput_mib_s is None or throughput_mib_s <= 0:
        return 0.0

    return max(0.0, throughput_mib_s)


def calculate_disk_score(read_mb_s: float = None, write_mb_s: float = None) -> float:
    """
    Calculate Disk score from fio read/write bandwidth.

    Formula: read_mb_s + write_mb_s (raw value)
    No normalization applied.

    Example: (695 + 695) MB/s → 1390 score
    """
    if read_mb_s is None and write_mb_s is None:
        return 0.0

    read = read_mb_s if read_mb_s is not None and read_mb_s > 0 else 0.0
    write = write_mb_s if write_mb_s is not None and write_mb_s > 0 else 0.0

    return max(0.0, read + write)


def calculate_network_score(upload_mbps: float = None, download_mbps: float = None) -> float:
    """
    Calculate Network score from iperf3 upload/download speeds.

    Formula: upload_mbps + download_mbps (raw value)
    No normalization applied.

    Example: (484.67 + 390.13) Mbps → 874.8 score
    """
    if upload_mbps is None and download_mbps is None:
        return 0.0

    upload = upload_mbps if upload_mbps is not None and upload_mbps > 0 else 0.0
    download = download_mbps if download_mbps is not None and download_mbps > 0 else 0.0

    return max(0.0, upload + download)


def calculate_gpu_score(glmark2_score: int = None) -> float:
    """
    Calculate GPU score from glmark2 benchmark.

    Formula: glmark2_score (raw value)
    No normalization applied.

    Example: 2500 glmark2 → 2500 score
    """
    if glmark2_score is None or glmark2_score <= 0:
        return 0.0

    return max(0.0, float(glmark2_score))


def calculate_global_score(
    cpu_score: float = None,
    memory_score: float = None,
    disk_score: float = None,
    network_score: float = None,
    gpu_score: float = None
) -> float:
    """
    Calculate global score from component scores using configured weights.

    Returns:
        float: Global score (0-100)
    """
    scores = []
    weights = []

    if cpu_score is not None:
        scores.append(cpu_score)
        weights.append(settings.SCORE_WEIGHT_CPU)

    if memory_score is not None:
        scores.append(memory_score)
        weights.append(settings.SCORE_WEIGHT_MEMORY)

    if disk_score is not None:
        scores.append(disk_score)
        weights.append(settings.SCORE_WEIGHT_DISK)

    if network_score is not None:
        scores.append(network_score)
        weights.append(settings.SCORE_WEIGHT_NETWORK)

    if gpu_score is not None:
        scores.append(gpu_score)
        weights.append(settings.SCORE_WEIGHT_GPU)

    if not scores:
        return 0.0

    # Normalize weights if not all components are present
    total_weight = sum(weights)
    if total_weight == 0:
        return 0.0

    # Calculate weighted average
    weighted_sum = sum(score * weight for score, weight in zip(scores, weights))
    global_score = weighted_sum / total_weight

    # Ensure non-negative
    return max(0.0, global_score)


def validate_score(score: float) -> bool:
    """
    Validate that a score is within acceptable range.

    Args:
        score: Score value to validate

    Returns:
        bool: True if score is valid (>= 0 or None)
    """
    if score is None:
        return True

    return score >= 0.0
