use std::sync::Arc;

use chrono::{DateTime, SecondsFormat, Utc};

use crate::tree::ast::expression::{Expression, NullLiteral};
use crate::tree::ast::ops::BinaryOp;
use crate::tree::builder::{call, null, BinaryOperatorBuilder, ExpressionBuilder};

/// A time range with optional start and end bounds.
///
/// Used for resolving dynamic time ranges in queries (e.g., `[-1h..]`).
/// Converts to an AST [`Expression`] via [`From`], producing a range expression
/// like `ts('2024-01-01T00:00:00.000Z')..ts('2024-01-02T00:00:00.000Z')`.
#[derive(Debug, Clone, Default)]
pub struct TimeRange {
    pub start: Option<DateTime<Utc>>,
    pub end: Option<DateTime<Utc>>,
}

impl From<TimeRange> for Expression {
    fn from(range: TimeRange) -> Self {
        let ts_call =
            |dt: DateTime<Utc>| call("ts").arg(dt.to_rfc3339_opts(SecondsFormat::Millis, true));
        match (range.start, range.end) {
            (Some(start), Some(end)) => {
                BinaryOperatorBuilder::new(BinaryOp::Range, ts_call(start), ts_call(end)).build()
            }
            (Some(start), None) => {
                BinaryOperatorBuilder::new(BinaryOp::Range, ts_call(start), null()).build()
            }
            (None, Some(end)) => {
                BinaryOperatorBuilder::new(BinaryOp::Range, null(), ts_call(end)).build()
            }
            (None, None) => Expression::from_kind(NullLiteral),
        }
    }
}

impl From<TimeRange> for Arc<Expression> {
    fn from(range: TimeRange) -> Self {
        Arc::new(Expression::from(range))
    }
}
