"""Scoring configuration persistence service."""

# Enable future language features for compatibility
from __future__ import annotations

# Import uuid
import uuid

# Import Any from typing
from typing import Any

# Import Session from sqlalchemy.orm
from sqlalchemy.orm import Session

# Import settings from app.config
from app.config import settings

# Import ScoringWeights from app.domain.value_objects.scoring_weights
from app.domain.value_objects.scoring_weights import ScoringWeights

# Import ScoringConfig from app.models.scoring_config
from app.models.scoring_config import ScoringConfig


# Define function _row_recency
def _row_recency(row: ScoringConfig) -> float:
    # Return float(getattr(row, "weight_recency", None) or getattr(row, "weight_...
    return float(getattr(row, "weight_recency", None) or getattr(row, "weight_freshness", 10.0))


# Define function _row_severity
def _row_severity(row: ScoringConfig) -> float:
    # Return float(
    return float(
        getattr(row, "weight_severity", None)
        or getattr(row, "weight_platform_diversity", 10.0)
    )


# Define function get_scoring_weights
def get_scoring_weights(db: Session) -> ScoringWeights:
    """Return the active scoring weights from the database or env defaults."""
    # Assign row = db.query(ScoringConfig).first()
    row = db.query(ScoringConfig).first()
    # Check: row is not None
    if row is not None:
        # Return ScoringWeights(
        return ScoringWeights(
            # Keyword argument: tests
            tests=row.weight_tests,
            # Keyword argument: detection_rules
            detection_rules=row.weight_detection_rules,
            # Keyword argument: d3fend
            d3fend=row.weight_d3fend,
            # Keyword argument: recency
            recency=_row_recency(row),
            # Keyword argument: severity
            severity=_row_severity(row),
        )

    # Return ScoringWeights(
    return ScoringWeights(
        # Keyword argument: tests
        tests=float(settings.SCORING_WEIGHT_TESTS),
        # Keyword argument: detection_rules
        detection_rules=float(settings.SCORING_WEIGHT_DETECTION_RULES),
        # Keyword argument: d3fend
        d3fend=float(settings.SCORING_WEIGHT_D3FEND),
        # Keyword argument: recency
        recency=float(
            getattr(settings, "SCORING_WEIGHT_RECENCY", settings.SCORING_WEIGHT_FRESHNESS)
        ),
        # Keyword argument: severity
        severity=float(
            getattr(settings, "SCORING_WEIGHT_SEVERITY", settings.SCORING_WEIGHT_PLATFORM_DIVERSITY)
        ),
    )


# Define function update_scoring_weights
def update_scoring_weights(
    # Entry: db
    db: Session,
    *,
    # Entry: tests
    tests: float | None = None,
    # Entry: detection_rules
    detection_rules: float | None = None,
    # Entry: d3fend
    d3fend: float | None = None,
    # Entry: recency
    recency: float | None = None,
    # Entry: severity
    severity: float | None = None,
    # Entry: freshness
    freshness: float | None = None,
    # Entry: platform_diversity
    platform_diversity: float | None = None,
    # Entry: updated_by
    updated_by: uuid.UUID | None = None,
) -> dict[str, Any]:
    """Upsert scoring weights. Does not commit."""
    # Check: freshness is not None and recency is None
    if freshness is not None and recency is None:
        # Assign recency = freshness
        recency = freshness
    # Check: platform_diversity is not None and severity is None
    if platform_diversity is not None and severity is None:
        # Assign severity = platform_diversity
        severity = platform_diversity

    # Assign current = get_scoring_weights(db)
    current = get_scoring_weights(db)

    # Assign new = ScoringWeights(
    new = ScoringWeights(
        # Keyword argument: tests
        tests=tests if tests is not None else current.tests,
        # Keyword argument: detection_rules
        detection_rules=detection_rules if detection_rules is not None else current.detection_rules,
        # Keyword argument: d3fend
        d3fend=d3fend if d3fend is not None else current.d3fend,
        # Keyword argument: recency
        recency=recency if recency is not None else current.recency,
        # Keyword argument: severity
        severity=severity if severity is not None else current.severity,
    )

    # Assign row = db.query(ScoringConfig).first()
    row = db.query(ScoringConfig).first()
    # Check: row is None
    if row is None:
        # Assign row = ScoringConfig()
        row = ScoringConfig()
        # Stage new record(s) for database insertion
        db.add(row)

    # Assign row.weight_tests = new.tests
    row.weight_tests = new.tests
    # Assign row.weight_detection_rules = new.detection_rules
    row.weight_detection_rules = new.detection_rules
    # Assign row.weight_d3fend = new.d3fend
    row.weight_d3fend = new.d3fend
    # Check: hasattr(row, "weight_recency")
    if hasattr(row, "weight_recency"):
        # Assign row.weight_recency = new.recency
        row.weight_recency = new.recency
    # Alternative: hasattr(row, "weight_freshness")
    elif hasattr(row, "weight_freshness"):
        # Assign row.weight_freshness = new.recency
        row.weight_freshness = new.recency
    # Check: hasattr(row, "weight_severity")
    if hasattr(row, "weight_severity"):
        # Assign row.weight_severity = new.severity
        row.weight_severity = new.severity
    # Alternative: hasattr(row, "weight_platform_diversity")
    elif hasattr(row, "weight_platform_diversity"):
        # Assign row.weight_platform_diversity = new.severity
        row.weight_platform_diversity = new.severity
    # Check: updated_by is not None and hasattr(row, "updated_by")
    if updated_by is not None and hasattr(row, "updated_by"):
        # Assign row.updated_by = updated_by
        row.updated_by = updated_by

    # Return _weights_dict(new)
    return _weights_dict(new)


# Define function get_weights_dict
def get_weights_dict(db: Session) -> dict[str, Any]:
    """Return current weights as a serialisable dict."""
    # Return _weights_dict(get_scoring_weights(db))
    return _weights_dict(get_scoring_weights(db))


# Define function _weights_dict
def _weights_dict(w: ScoringWeights) -> dict[str, Any]:
    # Assign weights = {
    weights = {
        # Literal argument value
        "tests": w.tests,
        # Literal argument value
        "detection_rules": w.detection_rules,
        # Literal argument value
        "d3fend": w.d3fend,
        # Literal argument value
        "recency": w.recency,
        # Literal argument value
        "severity": w.severity,
        # Legacy keys for older clients
        "freshness": w.recency,
        # Literal argument value
        "platform_diversity": w.severity,
    }
    # Return {
    return {
        # Literal argument value
        "weights": weights,
        # Literal argument value
        "total": sum(
            [w.tests, w.detection_rules, w.d3fend, w.recency, w.severity]
        ),
    }
