"""Measurement service - pass/fail calculation, data storage."""
from decimal import Decimal

from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

from src.backend.models.orm.measurement import Measurement
from src.backend.models.orm.task import RecipeSubtask


def calculate_pass_fail(
    value: float, subtask: RecipeSubtask
) -> tuple[str, float | None]:
    """Calculate pass/fail status and deviation based on tolerances.

    Returns (status, deviation) where status is 'pass', 'warning', or 'fail'.

    Logic:
    - If value is outside UTL/LTL -> 'fail'
    - If value is outside UWL/LWL but inside UTL/LTL -> 'warning'
    - Otherwise -> 'pass'
    """
    deviation = None
    if subtask.nominal is not None:
        deviation = float(Decimal(str(value)) - Decimal(str(subtask.nominal)))

    # Check fail (outside tolerance limits)
    if subtask.utl is not None and value > float(subtask.utl):
        return "fail", deviation
    if subtask.ltl is not None and value < float(subtask.ltl):
        return "fail", deviation

    # Check warning (outside warning limits)
    if subtask.uwl is not None and value > float(subtask.uwl):
        return "warning", deviation
    if subtask.lwl is not None and value < float(subtask.lwl):
        return "warning", deviation

    return "pass", deviation


async def save_measurement(
    db: AsyncSession,
    subtask_id: int,
    version_id: int,
    measured_by: int,
    value: float,
    lot_number: str | None = None,
    serial_number: str | None = None,
    input_method: str = "manual",
) -> Measurement:
    """Save a single measurement with auto-calculated pass/fail."""
    # Get subtask for tolerance values
    result = await db.execute(
        select(RecipeSubtask).where(RecipeSubtask.id == subtask_id)
    )
    subtask = result.scalar_one_or_none()
    if subtask is None:
        raise ValueError(f"Subtask {subtask_id} not found")

    pass_fail, deviation = calculate_pass_fail(value, subtask)

    measurement = Measurement(
        subtask_id=subtask_id,
        version_id=version_id,
        measured_by=measured_by,
        value=value,
        pass_fail=pass_fail,
        deviation=deviation,
        lot_number=lot_number,
        serial_number=serial_number,
        input_method=input_method,
    )
    db.add(measurement)
    await db.flush()
    await db.refresh(measurement)
    return measurement
