//! Eval implementations for unary operators

use hamelin_lib::func::defs::{
    UnaryMinus, UnaryPlus, UnaryRangePostfix, UnaryRangePrefix, UnaryRangePrefixInclusive,
};

use crate::registry::EvalRegistry;
use crate::value::{DecimalValue, RangeValue, Value};

/// Register all unary operator eval implementations.
pub fn register(registry: &mut EvalRegistry) {
    // UnaryMinus: -x negates numeric, interval, and rows values
    registry.register_eval::<UnaryMinus>(|mut bindings| {
        let x = bindings.take()?;
        match x {
            Value::Int(i) => i
                .checked_neg()
                .map(Value::Int)
                .ok_or_else(|| anyhow::anyhow!("integer overflow: cannot negate {}", i)),
            Value::Double(d) => Ok(Value::Double(-d)),
            Value::Rows(r) => r
                .checked_neg()
                .map(Value::Rows)
                .ok_or_else(|| anyhow::anyhow!("integer overflow: cannot negate {} rows", r)),
            Value::Decimal(d) => d
                .unscaled
                .checked_neg()
                .map(|unscaled| Value::Decimal(DecimalValue::new(unscaled, d.scale)))
                .ok_or_else(|| anyhow::anyhow!("decimal overflow: cannot negate {:?}", d)),
            Value::Interval(i) => i
                .checked_mul(-1)
                .map(Value::Interval)
                .ok_or_else(|| anyhow::anyhow!("interval overflow: cannot negate {:?}", i)),
            Value::CalendarInterval(months) => months
                .checked_neg()
                .map(Value::CalendarInterval)
                .ok_or_else(|| {
                    anyhow::anyhow!(
                        "calendar interval overflow: cannot negate {} months",
                        months
                    )
                }),
            Value::Null => Ok(Value::Null),
            _ => anyhow::bail!("UnaryMinus not supported for {:?}", x),
        }
    });

    // UnaryPlus: +x is identity for numeric, interval, and rows values
    registry.register_eval::<UnaryPlus>(|mut bindings| {
        let x = bindings.take()?;
        match x {
            Value::Int(_)
            | Value::Double(_)
            | Value::Rows(_)
            | Value::Decimal(_)
            | Value::Interval(_)
            | Value::CalendarInterval(_)
            | Value::Null => Ok(x),
            _ => anyhow::bail!("UnaryPlus not supported for {:?}", x),
        }
    });

    // UnaryRangePrefix: ..x creates a range with upper bound only
    registry.register_eval::<UnaryRangePrefix>(|mut bindings| {
        let x = bindings.take()?;
        Ok(Value::Range(Box::new(RangeValue {
            lower: None,
            upper: Some(x),
        })))
    });

    // UnaryRangePostfix: x.. creates a range with lower bound only
    registry.register_eval::<UnaryRangePostfix>(|mut bindings| {
        let x = bindings.take()?;
        Ok(Value::Range(Box::new(RangeValue {
            lower: Some(x),
            upper: None,
        })))
    });

    // UnaryRangePrefixInclusive: ..=x creates an inclusive range with upper bound only
    registry.register_eval::<UnaryRangePrefixInclusive>(|mut bindings| {
        let x = bindings.take()?;
        Ok(Value::Range(Box::new(RangeValue {
            lower: None,
            upper: Some(x),
        })))
    });

    // No reverse eval for unary operators
}
