//! PromQL query engine
//!
//! Implements a subset of PromQL for querying time-series data.
//! Provides instant and range query execution with basic aggregations.

use axum::{
    extract::{Path, Query, State},
    http::StatusCode,
    response::{IntoResponse, Json},
    routing::get,
    Router,
};
use nightlight_types::{Error, Label, Result, Sample, SeriesId, TimeSeries};
use parking_lot::Mutex;
use promql_parser::{
    label::{MatchOp, Matchers},
    parser::{
        AggregateExpr, BinModifier, BinaryExpr, Call, Expr, LabelModifier, MatrixSelector,
        NumberLiteral, UnaryExpr, VectorMatchCardinality, VectorSelector,
    },
};
use regex::Regex;
use serde::{Deserialize, Serialize};
use std::collections::{BTreeMap, HashMap, VecDeque};
use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::Arc;
use std::time::Instant;
use tokio::sync::RwLock;
#[cfg(test)]
use tracing::info;
use tracing::{debug, error};

const QUERY_DURATION_HISTORY_LIMIT: usize = 512;

/// Query service state
#[derive(Clone)]
pub struct QueryService {
    // Reference to queryable storage (shared with ingestion)
    storage: Arc<RwLock<QueryableStorage>>,
    metrics: Arc<QueryMetrics>,
}

/// In-memory queryable storage (reads from ingestion buffer)
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct QueryableStorage {
    // Series metadata indexed by SeriesId
    pub series: HashMap<SeriesId, TimeSeries>,
    // Inverted index: label name -> label value -> [SeriesId]
    pub label_index: HashMap<String, HashMap<String, Vec<SeriesId>>>,
}

#[derive(Debug)]
pub struct QueryMetrics {
    queries_total: AtomicU64,
    queries_failed: AtomicU64,
    queries_active: AtomicU64,
    durations_ms: Mutex<VecDeque<u64>>,
}

#[derive(Debug, Clone, Copy, Default)]
pub struct QueryMetricsSnapshot {
    pub queries_total: u64,
    pub queries_failed: u64,
    pub queries_active: u64,
    pub query_duration_p50: f64,
    pub query_duration_p95: f64,
    pub query_duration_p99: f64,
}

#[derive(Debug, Clone)]
enum EvalValue {
    Vector(Vec<TimeSeries>),
    Scalar(f64),
}

#[derive(Debug, Clone)]
struct MetadataMatcher {
    name: String,
    op: MatchOp,
    value: String,
}

impl QueryService {
    pub fn new() -> Self {
        Self {
            storage: Arc::new(RwLock::new(QueryableStorage {
                series: HashMap::new(),
                label_index: HashMap::new(),
            })),
            metrics: Arc::new(QueryMetrics::new()),
        }
    }

    /// Create QueryService from existing shared storage
    pub fn from_storage(storage: Arc<RwLock<QueryableStorage>>) -> Self {
        Self {
            storage,
            metrics: Arc::new(QueryMetrics::new()),
        }
    }

    /// Create QueryService and load persistent state from disk if it exists
    #[cfg(test)]
    pub fn new_with_persistence(data_path: &std::path::Path) -> Result<Self> {
        let storage = QueryableStorage::load_from_file(data_path)?;
        info!(
            "Loaded {} series from persistent storage",
            storage.series.len()
        );

        Ok(Self {
            storage: Arc::new(RwLock::new(storage)),
            metrics: Arc::new(QueryMetrics::new()),
        })
    }

    /// Save current storage state to disk
    #[cfg(test)]
    pub async fn save_to_disk(&self, data_path: &std::path::Path) -> Result<()> {
        let storage = self.storage.read().await;
        storage.save_to_file(data_path)?;
        debug!(
            "Saved {} series to persistent storage",
            storage.series.len()
        );
        Ok(())
    }

    /// Create Axum router for query endpoints
    pub fn router(self) -> Router {
        Router::new()
            .route("/api/v1/query", get(handle_instant_query))
            .route("/api/v1/query_range", get(handle_range_query))
            .route("/api/v1/label/:label_name/values", get(handle_label_values))
            .route("/api/v1/series", get(handle_series))
            .with_state(self)
    }

    pub fn metrics(&self) -> Arc<QueryMetrics> {
        Arc::clone(&self.metrics)
    }

    /// Execute an instant query at a specific timestamp
    pub async fn execute_instant_query(&self, query: &str, time: i64) -> Result<QueryResult> {
        debug!("Executing instant query: {} at time {}", query, time);
        let started = self.metrics.begin_query();

        // Parse PromQL expression
        let expr = promql_parser::parser::parse(query)
            .map_err(|e| Error::Query(format!("Parse error: {:?}", e)));
        let expr = match expr {
            Ok(expr) => expr,
            Err(error) => {
                self.metrics.finish_query(started, false);
                return Err(error);
            }
        };

        // Execute the expression
        let storage = self.storage.read().await;
        let result = self.evaluate_value(&expr, time, time, 0, &storage).await;
        let success = result.is_ok();
        self.metrics.finish_query(started, success);
        let result = result?;

        Ok(instant_query_from_eval_value(result, time))
    }

    /// Execute a range query over a time range with step
    pub async fn execute_range_query(
        &self,
        query: &str,
        start: i64,
        end: i64,
        step: i64,
    ) -> Result<RangeQueryResult> {
        debug!(
            "Executing range query: {} from {} to {} step {}",
            query, start, end, step
        );
        let started = self.metrics.begin_query();

        if step <= 0 {
            self.metrics.finish_query(started, false);
            return Err(Error::InvalidTimeRange(
                "range query step must be greater than zero".to_string(),
            ));
        }
        if end < start {
            self.metrics.finish_query(started, false);
            return Err(Error::InvalidTimeRange(
                "range query end must be greater than or equal to start".to_string(),
            ));
        }

        // Parse PromQL expression
        let expr = promql_parser::parser::parse(query)
            .map_err(|e| Error::Query(format!("Parse error: {:?}", e)));
        let expr = match expr {
            Ok(expr) => expr,
            Err(error) => {
                self.metrics.finish_query(started, false);
                return Err(error);
            }
        };

        let storage = self.storage.read().await;
        let mut results: HashMap<String, RangeResult> = HashMap::new();

        // Evaluate at each step
        let mut current_time = start;
        while current_time <= end {
            let step_result = self
                .evaluate_value(&expr, current_time, end, step, &storage)
                .await;
            let step_result = match step_result {
                Ok(step_result) => step_result,
                Err(error) => {
                    self.metrics.finish_query(started, false);
                    return Err(error);
                }
            };

            append_range_step_result(&mut results, step_result, current_time);

            current_time += step;
        }

        let result = RangeQueryResult {
            result_type: "matrix".to_string(),
            result: results.into_values().collect(),
        };
        self.metrics.finish_query(started, true);
        Ok(result)
    }

    /// Evaluate a PromQL expression (recursive with boxing for async)
    fn evaluate_value<'a>(
        &'a self,
        expr: &'a Expr,
        time: i64,
        end_time: i64,
        step: i64,
        storage: &'a QueryableStorage,
    ) -> std::pin::Pin<Box<dyn std::future::Future<Output = Result<EvalValue>> + Send + 'a>> {
        Box::pin(async move {
            match expr {
                Expr::VectorSelector(selector) => {
                    // Vector selector: metric_name{label="value"}
                    self.evaluate_vector_selector(selector, time, storage)
                        .map(EvalValue::Vector)
                }
                Expr::MatrixSelector(selector) => {
                    // Range selector: metric_name[5m]
                    self.evaluate_matrix_selector(selector, time, storage)
                        .map(EvalValue::Vector)
                }
                Expr::Aggregate(agg) => {
                    // Aggregation: sum(metric), avg(metric), etc.
                    self.evaluate_aggregation(agg, time, end_time, step, storage)
                        .await
                        .map(EvalValue::Vector)
                }
                Expr::Call(call) => {
                    // Function call: rate(metric[5m]), etc.
                    self.evaluate_function(call, time, end_time, step, storage)
                        .await
                }
                Expr::Binary(binary) => {
                    // Binary operation: metric1 + metric2
                    self.evaluate_binary(binary, time, end_time, step, storage)
                        .await
                }
                Expr::NumberLiteral(NumberLiteral { val }) => Ok(EvalValue::Scalar(*val)),
                Expr::Paren(paren) => {
                    self.evaluate_value(&paren.expr, time, end_time, step, storage)
                        .await
                }
                Expr::Unary(unary) => {
                    self.evaluate_unary(unary, time, end_time, step, storage)
                        .await
                }
                _ => Err(Error::Query(format!(
                    "Unsupported expression type: {:?}",
                    expr
                ))),
            }
        })
    }

    /// Evaluate vector selector
    fn evaluate_vector_selector(
        &self,
        selector: &VectorSelector,
        time: i64,
        storage: &QueryableStorage,
    ) -> Result<Vec<TimeSeries>> {
        // Find all series matching the label matchers
        let matching_series: Vec<TimeSeries> = storage
            .series
            .values()
            .filter(|ts| self.matches_selector(ts, selector))
            .cloned()
            .map(|mut ts| {
                // Filter to get sample closest to query time
                ts.samples.retain(|s| s.timestamp <= time);
                // Keep only the most recent sample
                if let Some(last) = ts.samples.last().cloned() {
                    ts.samples = vec![last];
                }
                ts
            })
            .filter(|ts| !ts.samples.is_empty())
            .collect();

        Ok(matching_series)
    }

    /// Evaluate matrix selector (range selector)
    fn evaluate_matrix_selector(
        &self,
        selector: &MatrixSelector,
        time: i64,
        storage: &QueryableStorage,
    ) -> Result<Vec<TimeSeries>> {
        // Get the time range in milliseconds
        let range_ms = selector.range.as_millis() as i64;
        let start_time = time - range_ms;

        // Evaluate underlying vector selector
        let mut series = storage
            .series
            .values()
            .filter(|ts| self.matches_selector(ts, &selector.vs))
            .cloned()
            .collect::<Vec<_>>();

        // Filter samples to the time range
        for ts in &mut series {
            ts.samples
                .retain(|s| s.timestamp >= start_time && s.timestamp <= time);
        }

        // Remove empty series
        series.retain(|ts| !ts.samples.is_empty());

        Ok(series)
    }

    /// Evaluate aggregation (sum, avg, min, max, count)
    async fn evaluate_aggregation(
        &self,
        agg: &AggregateExpr,
        time: i64,
        end_time: i64,
        step: i64,
        storage: &QueryableStorage,
    ) -> Result<Vec<TimeSeries>> {
        let input_series = expect_vector(
            self.evaluate_value(&agg.expr, time, end_time, step, storage)
                .await?,
            "aggregation input must be a vector",
        )?;

        if input_series.is_empty() {
            return Ok(vec![]);
        }

        let mut groups: BTreeMap<String, (Vec<Label>, Vec<f64>)> = BTreeMap::new();
        for series in input_series {
            let Some(sample) = series.samples.last() else {
                continue;
            };

            let labels = aggregation_output_labels(&series.labels, agg.modifier.as_ref());
            let key = labels_key(&labels);
            groups
                .entry(key)
                .or_insert_with(|| (labels, Vec::new()))
                .1
                .push(sample.value);
        }

        let op = agg.op.to_string().to_lowercase();
        let mut results = Vec::new();
        for (labels, values) in groups.into_values() {
            if values.is_empty() {
                continue;
            }

            let aggregated_value = aggregate_values(&op, &values)?;
            results.push(TimeSeries {
                id: SeriesId(results.len() as u64),
                labels,
                samples: vec![Sample::new(time, aggregated_value)],
            });
        }

        Ok(results)
    }

    /// Evaluate function call (rate, irate, increase, histogram_quantile)
    async fn evaluate_function(
        &self,
        call: &Call,
        time: i64,
        end_time: i64,
        step: i64,
        storage: &QueryableStorage,
    ) -> Result<EvalValue> {
        let func_name = &call.func.name;

        match func_name.to_string().as_str() {
            "rate" => self
                .evaluate_rate(call, time, end_time, step, storage)
                .await
                .map(EvalValue::Vector),
            "irate" => self
                .evaluate_irate(call, time, end_time, step, storage)
                .await
                .map(EvalValue::Vector),
            "increase" => self
                .evaluate_increase(call, time, end_time, step, storage)
                .await
                .map(EvalValue::Vector),
            "histogram_quantile" => self
                .evaluate_histogram_quantile(call, time, end_time, step, storage)
                .await
                .map(EvalValue::Vector),
            _ => Err(Error::Query(format!("Unsupported function: {}", func_name))),
        }
    }

    /// Evaluate rate() function - calculates per-second average rate of increase
    async fn evaluate_rate(
        &self,
        call: &Call,
        time: i64,
        end_time: i64,
        step: i64,
        storage: &QueryableStorage,
    ) -> Result<Vec<TimeSeries>> {
        // rate() expects a range vector (MatrixSelector) as argument
        if call.args.args.is_empty() {
            return Err(Error::Query(
                "rate() requires a range vector argument".into(),
            ));
        }

        let arg = &call.args.args[0];
        let series_list = expect_vector(
            self.evaluate_value(arg, time, end_time, step, storage)
                .await?,
            "rate() requires a range vector argument",
        )?;

        // Apply rate calculation to each series
        let mut result = Vec::new();
        for series in series_list {
            if series.samples.len() < 2 {
                continue; // Need at least 2 samples for rate calculation
            }

            // Get first and last samples
            let first = &series.samples[0];
            let last = &series.samples[series.samples.len() - 1];

            // Calculate time range in seconds
            let duration_seconds = (last.timestamp - first.timestamp) as f64 / 1000.0;
            if duration_seconds <= 0.0 {
                continue;
            }

            // Calculate rate (per-second average)
            // For counter metrics, we should handle resets, but simplified here
            let value_diff = last.value - first.value;
            let rate = value_diff / duration_seconds;

            // Create result series with single sample at query time
            result.push(TimeSeries {
                id: series.id,
                labels: series.labels.clone(),
                samples: vec![Sample {
                    timestamp: time,
                    value: rate.max(0.0), // Rates can't be negative for counters
                }],
            });
        }

        Ok(result)
    }

    /// Evaluate irate() function - calculates instant rate using last two samples
    async fn evaluate_irate(
        &self,
        call: &Call,
        time: i64,
        end_time: i64,
        step: i64,
        storage: &QueryableStorage,
    ) -> Result<Vec<TimeSeries>> {
        // irate() expects a range vector (MatrixSelector) as argument
        if call.args.args.is_empty() {
            return Err(Error::Query(
                "irate() requires a range vector argument".into(),
            ));
        }

        let arg = &call.args.args[0];
        let series_list = expect_vector(
            self.evaluate_value(arg, time, end_time, step, storage)
                .await?,
            "irate() requires a range vector argument",
        )?;

        // Apply irate calculation to each series
        let mut result = Vec::new();
        for series in series_list {
            if series.samples.len() < 2 {
                continue; // Need at least 2 samples for irate calculation
            }

            // Get last two samples
            let second_last = &series.samples[series.samples.len() - 2];
            let last = &series.samples[series.samples.len() - 1];

            // Calculate time difference in seconds
            let duration_seconds = (last.timestamp - second_last.timestamp) as f64 / 1000.0;
            if duration_seconds <= 0.0 {
                continue;
            }

            // Calculate instant rate
            let value_diff = last.value - second_last.value;
            let rate = value_diff / duration_seconds;

            // Create result series with single sample at query time
            result.push(TimeSeries {
                id: series.id,
                labels: series.labels.clone(),
                samples: vec![Sample {
                    timestamp: time,
                    value: rate.max(0.0), // Rates can't be negative for counters
                }],
            });
        }

        Ok(result)
    }

    /// Evaluate increase() function - calculates total increase over time range
    async fn evaluate_increase(
        &self,
        call: &Call,
        time: i64,
        end_time: i64,
        step: i64,
        storage: &QueryableStorage,
    ) -> Result<Vec<TimeSeries>> {
        // increase() expects a range vector (MatrixSelector) as argument
        if call.args.args.is_empty() {
            return Err(Error::Query(
                "increase() requires a range vector argument".into(),
            ));
        }

        let arg = &call.args.args[0];
        let series_list = expect_vector(
            self.evaluate_value(arg, time, end_time, step, storage)
                .await?,
            "increase() requires a range vector argument",
        )?;

        // Apply increase calculation to each series
        let mut result = Vec::new();
        for series in series_list {
            if series.samples.len() < 2 {
                continue; // Need at least 2 samples for increase calculation
            }

            // Get first and last samples
            let first = &series.samples[0];
            let last = &series.samples[series.samples.len() - 1];

            // Calculate total increase
            // For counter metrics, we should handle resets, but simplified here
            let increase = last.value - first.value;

            // Create result series with single sample at query time
            result.push(TimeSeries {
                id: series.id,
                labels: series.labels.clone(),
                samples: vec![Sample {
                    timestamp: time,
                    value: increase.max(0.0), // Increase can't be negative for counters
                }],
            });
        }

        Ok(result)
    }

    /// Evaluate histogram_quantile() from Prometheus-style cumulative buckets.
    async fn evaluate_histogram_quantile(
        &self,
        call: &Call,
        time: i64,
        end_time: i64,
        step: i64,
        storage: &QueryableStorage,
    ) -> Result<Vec<TimeSeries>> {
        if call.args.args.len() != 2 {
            return Err(Error::Query(
                "histogram_quantile() requires a scalar quantile and a bucket vector".into(),
            ));
        }

        let quantile = expect_scalar(
            self.evaluate_value(&call.args.args[0], time, end_time, step, storage)
                .await?,
            "histogram_quantile() requires a scalar quantile",
        )?;
        if !(0.0..=1.0).contains(&quantile) {
            return Err(Error::Query(format!(
                "histogram_quantile() quantile must be within [0, 1], got {quantile}"
            )));
        }

        let buckets = expect_vector(
            self.evaluate_value(&call.args.args[1], time, end_time, step, storage)
                .await?,
            "histogram_quantile() requires a bucket vector",
        )?;

        let mut grouped: BTreeMap<String, (Vec<Label>, Vec<(f64, f64)>)> = BTreeMap::new();
        for series in buckets {
            let Some(sample) = series.samples.last() else {
                continue;
            };
            let Some(le) = series.get_label("le") else {
                continue;
            };
            let upper_bound = parse_histogram_bound(le)?;
            let labels = histogram_output_labels(&series.labels);
            let key = labels_key(&labels);
            grouped
                .entry(key)
                .or_insert_with(|| (labels, Vec::new()))
                .1
                .push((upper_bound, sample.value));
        }

        let mut results = Vec::new();
        for (labels, mut buckets) in grouped.into_values() {
            buckets.sort_by(|(lhs, _), (rhs, _)| lhs.total_cmp(rhs));
            let value = histogram_quantile_value(quantile, &buckets)?;
            results.push(TimeSeries {
                id: SeriesId(results.len() as u64),
                labels,
                samples: vec![Sample::new(time, value)],
            });
        }

        Ok(results)
    }

    /// Evaluate binary operations for scalar/vector arithmetic and one-to-one vector matching.
    async fn evaluate_binary(
        &self,
        binary: &BinaryExpr,
        time: i64,
        end_time: i64,
        step: i64,
        storage: &QueryableStorage,
    ) -> Result<EvalValue> {
        if let Some(modifier) = &binary.modifier {
            if !matches!(modifier.card, VectorMatchCardinality::OneToOne) {
                return Err(Error::Query(
                    "many-to-one and many-to-many vector matching are not supported yet".into(),
                ));
            }
        }

        let lhs = self
            .evaluate_value(&binary.lhs, time, end_time, step, storage)
            .await?;
        let rhs = self
            .evaluate_value(&binary.rhs, time, end_time, step, storage)
            .await?;

        match (lhs, rhs) {
            (EvalValue::Scalar(lhs), EvalValue::Scalar(rhs)) => {
                evaluate_scalar_binary(binary, lhs, rhs).map(EvalValue::Scalar)
            }
            (EvalValue::Vector(lhs), EvalValue::Scalar(rhs)) => {
                evaluate_vector_scalar_binary(binary, lhs, rhs, true).map(EvalValue::Vector)
            }
            (EvalValue::Scalar(lhs), EvalValue::Vector(rhs)) => {
                evaluate_vector_scalar_binary(binary, rhs, lhs, false).map(EvalValue::Vector)
            }
            (EvalValue::Vector(lhs), EvalValue::Vector(rhs)) => {
                evaluate_vector_vector_binary(binary, lhs, rhs).map(EvalValue::Vector)
            }
        }
    }

    async fn evaluate_unary(
        &self,
        unary: &UnaryExpr,
        time: i64,
        end_time: i64,
        step: i64,
        storage: &QueryableStorage,
    ) -> Result<EvalValue> {
        match self
            .evaluate_value(&unary.expr, time, end_time, step, storage)
            .await?
        {
            EvalValue::Scalar(value) => Ok(EvalValue::Scalar(-value)),
            EvalValue::Vector(mut series) => {
                for entry in &mut series {
                    for sample in &mut entry.samples {
                        sample.value = -sample.value;
                    }
                }
                Ok(EvalValue::Vector(series))
            }
        }
    }

    fn matches_selector(&self, ts: &TimeSeries, selector: &VectorSelector) -> bool {
        if let Some(name) = selector.name.as_deref() {
            if ts.name() != Some(name) {
                return false;
            }
        }

        self.matches_matchers(ts, &selector.matchers)
    }

    fn matches_matchers(&self, ts: &TimeSeries, matchers: &Matchers) -> bool {
        if !matchers
            .matchers
            .iter()
            .all(|matcher| self.matcher_matches(ts, matcher))
        {
            return false;
        }

        if matchers.or_matchers.is_empty() {
            return true;
        }

        matchers.or_matchers.iter().any(|group| {
            group
                .iter()
                .all(|matcher| self.matcher_matches(ts, matcher))
        })
    }

    fn matcher_matches(&self, ts: &TimeSeries, matcher: &promql_parser::label::Matcher) -> bool {
        label_matcher_matches(ts.get_label(&matcher.name), &matcher.op, &matcher.value)
    }

    pub async fn series_metadata(
        &self,
        matchers: &[String],
        start: Option<i64>,
        end: Option<i64>,
    ) -> Result<Vec<HashMap<String, String>>> {
        let started = self.metrics.begin_query();
        let storage = self.storage.read().await;
        let series = self.matching_series(&storage, matchers, start, end);
        let success = series.is_ok();
        let result = series.map(|series| {
            series
                .into_iter()
                .map(|ts| {
                    ts.labels
                        .iter()
                        .map(|label| (label.name.clone(), label.value.clone()))
                        .collect()
                })
                .collect()
        });
        self.metrics.finish_query(started, success);
        result
    }

    pub async fn label_values_for_matchers(
        &self,
        label_name: &str,
        matchers: &[String],
        start: Option<i64>,
        end: Option<i64>,
    ) -> Result<Vec<String>> {
        let started = self.metrics.begin_query();
        let storage = self.storage.read().await;
        let values = self
            .matching_series(&storage, matchers, start, end)
            .map(|series| {
                let mut values: Vec<String> = series
                    .into_iter()
                    .filter_map(|series| series.get_label(label_name).map(str::to_string))
                    .collect();
                values.sort();
                values.dedup();
                values
            });
        self.metrics.finish_query(started, values.is_ok());
        values
    }

    fn matching_series(
        &self,
        storage: &QueryableStorage,
        matchers: &[String],
        start: Option<i64>,
        end: Option<i64>,
    ) -> Result<Vec<TimeSeries>> {
        let parsed_matchers = parse_metadata_matchers(matchers)?;
        Ok(storage
            .series
            .values()
            .filter(|series| series_matches(series, &parsed_matchers))
            .filter(|series| series_in_time_range(series, start, end))
            .cloned()
            .collect())
    }
}

impl QueryMetrics {
    fn new() -> Self {
        Self {
            queries_total: AtomicU64::new(0),
            queries_failed: AtomicU64::new(0),
            queries_active: AtomicU64::new(0),
            durations_ms: Mutex::new(VecDeque::with_capacity(QUERY_DURATION_HISTORY_LIMIT)),
        }
    }

    fn begin_query(&self) -> Instant {
        self.queries_total.fetch_add(1, Ordering::Relaxed);
        self.queries_active.fetch_add(1, Ordering::Relaxed);
        Instant::now()
    }

    fn finish_query(&self, started: Instant, success: bool) {
        if !success {
            self.queries_failed.fetch_add(1, Ordering::Relaxed);
        }
        self.queries_active.fetch_sub(1, Ordering::Relaxed);

        let elapsed_ms = started.elapsed().as_millis() as u64;
        let mut durations = self.durations_ms.lock();
        if durations.len() >= QUERY_DURATION_HISTORY_LIMIT {
            durations.pop_front();
        }
        durations.push_back(elapsed_ms);
    }

    pub fn snapshot(&self) -> QueryMetricsSnapshot {
        let mut sorted_durations: Vec<u64> = self.durations_ms.lock().iter().copied().collect();
        sorted_durations.sort_unstable();

        QueryMetricsSnapshot {
            queries_total: self.queries_total.load(Ordering::Relaxed),
            queries_failed: self.queries_failed.load(Ordering::Relaxed),
            queries_active: self.queries_active.load(Ordering::Relaxed),
            query_duration_p50: percentile(&sorted_durations, 0.50),
            query_duration_p95: percentile(&sorted_durations, 0.95),
            query_duration_p99: percentile(&sorted_durations, 0.99),
        }
    }
}

impl QueryableStorage {
    /// Add or update a time series in storage
    pub fn upsert_series(&mut self, series: TimeSeries) {
        // Update label index
        for label in &series.labels {
            let series_ids = self
                .label_index
                .entry(label.name.clone())
                .or_default()
                .entry(label.value.clone())
                .or_default();
            if !series_ids.contains(&series.id) {
                series_ids.push(series.id);
            }
        }

        // Upsert series
        self.series
            .entry(series.id)
            .and_modify(|existing| {
                // Merge samples (append new samples)
                existing.samples.extend(series.samples.clone());
                // Sort by timestamp
                existing.samples.sort_by_key(|s| s.timestamp);
                // Deduplicate
                existing.samples.dedup_by_key(|s| s.timestamp);
            })
            .or_insert(series);
    }

    /// Get label values for a specific label name
    #[cfg(test)]
    pub fn label_values(&self, label_name: &str) -> Vec<String> {
        let mut values: Vec<String> = self
            .label_index
            .get(label_name)
            .map(|values| values.keys().cloned().collect())
            .unwrap_or_default();
        values.sort();
        values
    }

    pub fn rebuild_index(&mut self) {
        self.label_index.clear();
        let series: Vec<TimeSeries> = self.series.values().cloned().collect();
        for series in series {
            for label in &series.labels {
                self.label_index
                    .entry(label.name.clone())
                    .or_default()
                    .entry(label.value.clone())
                    .or_default()
                    .push(series.id);
            }
        }
    }

    pub fn prune_before(&mut self, cutoff: i64) -> usize {
        let mut removed_samples = 0usize;
        self.series.retain(|_, series| {
            let before = series.samples.len();
            series.samples.retain(|sample| sample.timestamp >= cutoff);
            removed_samples += before.saturating_sub(series.samples.len());
            !series.samples.is_empty()
        });
        self.rebuild_index();
        removed_samples
    }
}

fn expect_vector(value: EvalValue, message: &str) -> Result<Vec<TimeSeries>> {
    match value {
        EvalValue::Vector(series) => Ok(series),
        EvalValue::Scalar(_) => Err(Error::Query(message.to_string())),
    }
}

fn expect_scalar(value: EvalValue, message: &str) -> Result<f64> {
    match value {
        EvalValue::Scalar(value) => Ok(value),
        EvalValue::Vector(_) => Err(Error::Query(message.to_string())),
    }
}

fn instant_query_from_eval_value(value: EvalValue, time: i64) -> QueryResult {
    match value {
        EvalValue::Scalar(value) => QueryResult {
            result_type: "scalar".to_string(),
            result: vec![InstantQueryResult {
                metric: HashMap::new(),
                value: Some((time, value)),
            }],
        },
        EvalValue::Vector(series) => QueryResult {
            result_type: "vector".to_string(),
            result: series
                .into_iter()
                .map(|ts| InstantQueryResult {
                    metric: labels_to_map(&ts.labels),
                    value: ts
                        .samples
                        .last()
                        .map(|sample| (sample.timestamp, sample.value)),
                })
                .collect(),
        },
    }
}

fn append_range_step_result(
    results: &mut HashMap<String, RangeResult>,
    step_result: EvalValue,
    time: i64,
) {
    match step_result {
        EvalValue::Scalar(value) => {
            let entry = results
                .entry("__scalar__".to_string())
                .or_insert_with(|| RangeResult {
                    metric: HashMap::new(),
                    values: Vec::new(),
                });
            entry.values.push((time, value));
        }
        EvalValue::Vector(series) => {
            for ts in series {
                let key = labels_key(&ts.labels);
                let metric = labels_to_map(&ts.labels);
                let entry = results.entry(key).or_insert_with(|| RangeResult {
                    metric,
                    values: Vec::new(),
                });
                for sample in ts.samples {
                    entry.values.push((sample.timestamp, sample.value));
                }
            }
        }
    }
}

fn labels_to_map(labels: &[Label]) -> HashMap<String, String> {
    labels
        .iter()
        .map(|label| (label.name.clone(), label.value.clone()))
        .collect()
}

fn normalize_labels(mut labels: Vec<Label>) -> Vec<Label> {
    labels.sort_by(|lhs, rhs| lhs.name.cmp(&rhs.name).then(lhs.value.cmp(&rhs.value)));
    labels
}

fn labels_key(labels: &[Label]) -> String {
    let mut pairs: Vec<(String, String)> = labels
        .iter()
        .map(|label| (label.name.clone(), label.value.clone()))
        .collect();
    pairs.sort();
    pairs
        .into_iter()
        .map(|(name, value)| format!("{name}={value}"))
        .collect::<Vec<_>>()
        .join(",")
}

fn aggregate_values(op: &str, values: &[f64]) -> Result<f64> {
    match op {
        "sum" => Ok(values.iter().sum()),
        "avg" => Ok(values.iter().sum::<f64>() / values.len() as f64),
        "min" => Ok(values.iter().copied().fold(f64::INFINITY, f64::min)),
        "max" => Ok(values.iter().copied().fold(f64::NEG_INFINITY, f64::max)),
        "count" => Ok(values.len() as f64),
        other => Err(Error::Query(format!("Unsupported aggregation: {other}"))),
    }
}

fn aggregation_output_labels(labels: &[Label], modifier: Option<&LabelModifier>) -> Vec<Label> {
    match modifier {
        None => Vec::new(),
        Some(LabelModifier::Include(group)) => normalize_labels(
            labels
                .iter()
                .filter(|label| group.labels.iter().any(|name| name == &label.name))
                .cloned()
                .collect(),
        ),
        Some(LabelModifier::Exclude(group)) => normalize_labels(
            labels
                .iter()
                .filter(|label| label.name != "__name__")
                .filter(|label| !group.labels.iter().any(|name| name == &label.name))
                .cloned()
                .collect(),
        ),
    }
}

fn histogram_output_labels(labels: &[Label]) -> Vec<Label> {
    normalize_labels(
        labels
            .iter()
            .filter(|label| label.name != "__name__" && label.name != "le")
            .cloned()
            .collect(),
    )
}

fn parse_histogram_bound(value: &str) -> Result<f64> {
    match value {
        "+Inf" | "Inf" | "+inf" | "inf" => Ok(f64::INFINITY),
        _ => value.parse::<f64>().map_err(|error| {
            Error::Query(format!("invalid histogram bucket bound {value:?}: {error}"))
        }),
    }
}

fn histogram_quantile_value(quantile: f64, buckets: &[(f64, f64)]) -> Result<f64> {
    let Some((_, total_count)) = buckets.last() else {
        return Err(Error::Query(
            "histogram_quantile() requires at least one bucket".into(),
        ));
    };
    if *total_count <= 0.0 {
        return Ok(0.0);
    }

    let target = quantile * total_count;
    let mut lower_bound = 0.0;
    let mut previous_count = 0.0;

    for (upper_bound, count) in buckets {
        if *count >= target {
            if upper_bound.is_infinite() {
                return Ok(lower_bound);
            }

            let bucket_count = (*count - previous_count).max(0.0);
            if bucket_count == 0.0 {
                return Ok(*upper_bound);
            }

            let fraction = ((target - previous_count) / bucket_count).clamp(0.0, 1.0);
            return Ok(lower_bound + (upper_bound - lower_bound) * fraction);
        }

        lower_bound = *upper_bound;
        previous_count = *count;
    }

    Ok(lower_bound)
}

fn evaluate_scalar_binary(binary: &BinaryExpr, lhs: f64, rhs: f64) -> Result<f64> {
    let op = binary.op.to_string();
    if is_set_operator(&op) {
        return Err(Error::Query(format!("Unsupported set operator: {op}")));
    }

    if is_comparison_operator(&op) {
        if !binary.return_bool() {
            return Err(Error::Query(
                "scalar comparisons require the bool modifier".into(),
            ));
        }

        return Ok(if compare_values(&op, lhs, rhs)? {
            1.0
        } else {
            0.0
        });
    }

    arithmetic_value(&op, lhs, rhs)
}

fn evaluate_vector_scalar_binary(
    binary: &BinaryExpr,
    series_list: Vec<TimeSeries>,
    scalar: f64,
    vector_on_lhs: bool,
) -> Result<Vec<TimeSeries>> {
    let mut results = Vec::new();
    for mut series in series_list {
        let labels = binary_result_labels(&series.labels, binary.modifier.as_ref());
        let mut samples = Vec::new();

        for sample in &mut series.samples {
            let (lhs, rhs) = if vector_on_lhs {
                (sample.value, scalar)
            } else {
                (scalar, sample.value)
            };
            let retained = sample.value;
            if let Some(value) = apply_binary_sample(binary, lhs, rhs, retained)? {
                samples.push(Sample::new(sample.timestamp, value));
            }
        }

        if !samples.is_empty() {
            results.push(TimeSeries {
                id: series.id,
                labels,
                samples,
            });
        }
    }

    Ok(results)
}

fn evaluate_vector_vector_binary(
    binary: &BinaryExpr,
    lhs_series: Vec<TimeSeries>,
    rhs_series: Vec<TimeSeries>,
) -> Result<Vec<TimeSeries>> {
    let lhs_index = build_vector_match_index(&lhs_series, binary.modifier.as_ref())?;
    let rhs_index = build_vector_match_index(&rhs_series, binary.modifier.as_ref())?;
    let mut results = Vec::new();

    for (key, lhs) in lhs_index {
        let Some(rhs) = rhs_index.get(&key) else {
            continue;
        };
        let Some(lhs_sample) = lhs.samples.last() else {
            continue;
        };
        let Some(rhs_sample) = rhs.samples.last() else {
            continue;
        };

        if let Some(value) =
            apply_binary_sample(binary, lhs_sample.value, rhs_sample.value, lhs_sample.value)?
        {
            results.push(TimeSeries {
                id: lhs.id,
                labels: binary_result_labels(&lhs.labels, binary.modifier.as_ref()),
                samples: vec![Sample::new(
                    lhs_sample.timestamp.max(rhs_sample.timestamp),
                    value,
                )],
            });
        }
    }

    Ok(results)
}

fn build_vector_match_index<'a>(
    series_list: &'a [TimeSeries],
    modifier: Option<&BinModifier>,
) -> Result<HashMap<String, &'a TimeSeries>> {
    let mut index = HashMap::new();
    for series in series_list {
        let key = vector_match_key(series, modifier);
        if index.insert(key.clone(), series).is_some() {
            return Err(Error::Query(format!(
                "duplicate vector match key {key:?}; many-to-one matching is not supported"
            )));
        }
    }
    Ok(index)
}

fn vector_match_key(series: &TimeSeries, modifier: Option<&BinModifier>) -> String {
    labels_key(&binary_result_labels(&series.labels, modifier))
}

fn binary_result_labels(labels: &[Label], modifier: Option<&BinModifier>) -> Vec<Label> {
    let selected = match modifier.and_then(|modifier| modifier.matching.as_ref()) {
        Some(LabelModifier::Include(group)) => labels
            .iter()
            .filter(|label| group.labels.iter().any(|name| name == &label.name))
            .cloned()
            .collect(),
        Some(LabelModifier::Exclude(group)) => labels
            .iter()
            .filter(|label| label.name != "__name__")
            .filter(|label| !group.labels.iter().any(|name| name == &label.name))
            .cloned()
            .collect(),
        None => labels
            .iter()
            .filter(|label| label.name != "__name__")
            .cloned()
            .collect(),
    };

    normalize_labels(selected)
}

fn apply_binary_sample(
    binary: &BinaryExpr,
    lhs: f64,
    rhs: f64,
    retained: f64,
) -> Result<Option<f64>> {
    let op = binary.op.to_string();
    if is_set_operator(&op) {
        return Err(Error::Query(format!("Unsupported set operator: {op}")));
    }

    if is_comparison_operator(&op) {
        let matched = compare_values(&op, lhs, rhs)?;
        if binary.return_bool() {
            return Ok(Some(if matched { 1.0 } else { 0.0 }));
        }
        return Ok(matched.then_some(retained));
    }

    Ok(Some(arithmetic_value(&op, lhs, rhs)?))
}

fn compare_values(op: &str, lhs: f64, rhs: f64) -> Result<bool> {
    match op {
        "==" => Ok(lhs == rhs),
        "!=" => Ok(lhs != rhs),
        ">" => Ok(lhs > rhs),
        ">=" => Ok(lhs >= rhs),
        "<" => Ok(lhs < rhs),
        "<=" => Ok(lhs <= rhs),
        other => Err(Error::Query(format!(
            "Unsupported comparison operator: {other}"
        ))),
    }
}

fn arithmetic_value(op: &str, lhs: f64, rhs: f64) -> Result<f64> {
    match op {
        "+" => Ok(lhs + rhs),
        "-" => Ok(lhs - rhs),
        "*" => Ok(lhs * rhs),
        "/" => Ok(lhs / rhs),
        "%" => Ok(lhs % rhs),
        "^" => Ok(lhs.powf(rhs)),
        "atan2" => Ok(lhs.atan2(rhs)),
        other => Err(Error::Query(format!(
            "Unsupported arithmetic operator: {other}"
        ))),
    }
}

fn is_comparison_operator(op: &str) -> bool {
    matches!(op, "==" | "!=" | ">" | ">=" | "<" | "<=")
}

fn is_set_operator(op: &str) -> bool {
    matches!(op, "and" | "or" | "unless")
}

fn percentile(values: &[u64], quantile: f64) -> f64 {
    if values.is_empty() {
        return 0.0;
    }

    let index = ((values.len() - 1) as f64 * quantile).round() as usize;
    values[index.min(values.len() - 1)] as f64
}

fn parse_metadata_matchers(matchers: &[String]) -> Result<Vec<MetadataMatcher>> {
    matchers
        .iter()
        .map(|matcher| parse_metadata_matcher(matcher))
        .collect()
}

fn parse_metadata_matcher(input: &str) -> Result<MetadataMatcher> {
    for operator in ["!~", "=~", "!=", "="] {
        if let Some((name, value)) = input.split_once(operator) {
            let name = name.trim();
            let raw_value = value.trim().trim_matches('"');
            if name.is_empty() {
                return Err(Error::Query(format!(
                    "invalid metadata matcher {input:?}: empty label name"
                )));
            }

            let op = match operator {
                "=" => MatchOp::Equal,
                "!=" => MatchOp::NotEqual,
                "=~" => MatchOp::Re(Regex::new(raw_value).map_err(|error| {
                    Error::Query(format!("invalid regex in matcher {input:?}: {error}"))
                })?),
                "!~" => MatchOp::NotRe(Regex::new(raw_value).map_err(|error| {
                    Error::Query(format!("invalid regex in matcher {input:?}: {error}"))
                })?),
                _ => unreachable!(),
            };

            return Ok(MetadataMatcher {
                name: name.to_string(),
                op,
                value: raw_value.to_string(),
            });
        }
    }

    Err(Error::Query(format!(
        "invalid metadata matcher {input:?}: expected one of =, !=, =~, !~"
    )))
}

fn series_matches(series: &TimeSeries, matchers: &[MetadataMatcher]) -> bool {
    matchers.iter().all(|matcher| {
        label_matcher_matches(series.get_label(&matcher.name), &matcher.op, &matcher.value)
    })
}

fn label_matcher_matches(label_value: Option<&str>, op: &MatchOp, expected: &str) -> bool {
    let value = label_value.unwrap_or("");
    match op {
        MatchOp::Equal => value == expected,
        MatchOp::NotEqual => value != expected,
        MatchOp::Re(regex) => regex.is_match(value),
        MatchOp::NotRe(regex) => !regex.is_match(value),
    }
}

fn series_in_time_range(series: &TimeSeries, start: Option<i64>, end: Option<i64>) -> bool {
    let Some((series_start, series_end)) = series.time_range() else {
        return true;
    };

    if let Some(start) = start {
        if series_end < start {
            return false;
        }
    }
    if let Some(end) = end {
        if series_start > end {
            return false;
        }
    }

    true
}

/// HTTP handler for instant queries
#[axum::debug_handler]
async fn handle_instant_query(
    State(service): State<QueryService>,
    Query(params): Query<InstantQueryParams>,
) -> (StatusCode, Json<QueryResponse>) {
    let time = params
        .time
        .unwrap_or_else(|| chrono::Utc::now().timestamp_millis());

    let response = match service.execute_instant_query(&params.query, time).await {
        Ok(result) => QueryResponse {
            status: "success".to_string(),
            data: Some(serde_json::to_value(result).unwrap()),
            error: None,
            error_type: None,
        },
        Err(e) => {
            error!("Query failed: {}", e);
            QueryResponse {
                status: "error".to_string(),
                data: None,
                error: Some(e.to_string()),
                error_type: Some("execution".to_string()),
            }
        }
    };

    (StatusCode::OK, Json(response))
}

/// HTTP handler for range queries
#[axum::debug_handler]
async fn handle_range_query(
    State(service): State<QueryService>,
    Query(params): Query<RangeQueryParams>,
) -> (StatusCode, Json<QueryResponse>) {
    let response = match service
        .execute_range_query(&params.query, params.start, params.end, params.step)
        .await
    {
        Ok(result) => QueryResponse {
            status: "success".to_string(),
            data: Some(serde_json::to_value(result).unwrap()),
            error: None,
            error_type: None,
        },
        Err(e) => {
            error!("Range query failed: {}", e);
            QueryResponse {
                status: "error".to_string(),
                data: None,
                error: Some(e.to_string()),
                error_type: Some("execution".to_string()),
            }
        }
    };

    (StatusCode::OK, Json(response))
}

/// HTTP handler for label values
async fn handle_label_values(
    State(service): State<QueryService>,
    Path(label_name): Path<String>,
    Query(params): Query<SeriesQueryParams>,
) -> impl IntoResponse {
    match service
        .label_values_for_matchers(&label_name, &params.matchers, params.start, params.end)
        .await
    {
        Ok(values) => (
            StatusCode::OK,
            Json(LabelValuesResponse {
                status: "success".to_string(),
                data: values,
            }),
        )
            .into_response(),
        Err(error) => (
            StatusCode::BAD_REQUEST,
            Json(serde_json::json!({
                "status": "error",
                "error": error.to_string(),
            })),
        )
            .into_response(),
    }
}

/// HTTP handler for series metadata
async fn handle_series(
    State(service): State<QueryService>,
    Query(params): Query<SeriesQueryParams>,
) -> impl IntoResponse {
    match service
        .series_metadata(&params.matchers, params.start, params.end)
        .await
    {
        Ok(series) => (
            StatusCode::OK,
            Json(SeriesResponse {
                status: "success".to_string(),
                data: series,
            }),
        )
            .into_response(),
        Err(error) => (
            StatusCode::BAD_REQUEST,
            Json(serde_json::json!({
                "status": "error",
                "error": error.to_string(),
            })),
        )
            .into_response(),
    }
}

// Request/Response Types

#[derive(Debug, Deserialize)]
struct InstantQueryParams {
    query: String,
    #[serde(default)]
    time: Option<i64>,
}

#[derive(Debug, Deserialize)]
struct RangeQueryParams {
    query: String,
    start: i64,
    end: i64,
    step: i64,
}

#[derive(Debug, Deserialize)]
struct SeriesQueryParams {
    #[serde(default)]
    #[serde(rename = "match[]")]
    matchers: Vec<String>,
    #[serde(default)]
    start: Option<i64>,
    #[serde(default)]
    end: Option<i64>,
}

#[derive(Debug, Serialize)]
struct QueryResponse {
    status: String,
    data: Option<serde_json::Value>,
    error: Option<String>,
    error_type: Option<String>,
}

#[derive(Debug, Clone, Serialize)]
pub struct QueryResult {
    #[serde(rename = "resultType")]
    pub result_type: String,
    pub result: Vec<InstantQueryResult>,
}

#[derive(Debug, Clone, Serialize)]
pub struct InstantQueryResult {
    pub metric: HashMap<String, String>,
    pub value: Option<(i64, f64)>,
}

#[derive(Debug, Clone, Serialize)]
pub struct RangeQueryResult {
    #[serde(rename = "resultType")]
    pub result_type: String,
    pub result: Vec<RangeResult>,
}

#[derive(Debug, Clone, Serialize)]
pub struct RangeResult {
    pub metric: HashMap<String, String>,
    pub values: Vec<(i64, f64)>,
}

#[derive(Debug, Serialize)]
struct LabelValuesResponse {
    status: String,
    data: Vec<String>,
}

#[derive(Debug, Serialize)]
struct SeriesResponse {
    status: String,
    data: Vec<HashMap<String, String>>,
}

impl Default for QueryService {
    fn default() -> Self {
        Self::new()
    }
}

impl QueryableStorage {
    /// Save storage state to disk using bincode serialization
    pub fn save_to_file(&self, path: &std::path::Path) -> Result<()> {
        use std::fs::File;
        use std::io::Write;

        // Serialize to bincode
        let encoded = bincode::serialize(self)
            .map_err(|e| Error::Storage(format!("Serialization failed: {}", e)))?;

        // Create parent directory if needed
        if let Some(parent) = path.parent() {
            std::fs::create_dir_all(parent)
                .map_err(|e| Error::Storage(format!("Failed to create directory: {}", e)))?;
        }

        // Write to file atomically (write to temp, then rename)
        let temp_path = path.with_extension("tmp");
        let mut file = File::create(&temp_path)
            .map_err(|e| Error::Storage(format!("Failed to create file: {}", e)))?;

        file.write_all(&encoded)
            .map_err(|e| Error::Storage(format!("Failed to write file: {}", e)))?;

        file.sync_all()
            .map_err(|e| Error::Storage(format!("Failed to sync file: {}", e)))?;

        std::fs::rename(&temp_path, path)
            .map_err(|e| Error::Storage(format!("Failed to rename file: {}", e)))?;

        Ok(())
    }

    /// Load storage state from disk using bincode deserialization
    pub fn load_from_file(path: &std::path::Path) -> Result<Self> {
        use std::fs::File;
        use std::io::Read;

        // Check if file exists
        if !path.exists() {
            return Ok(Self {
                series: HashMap::new(),
                label_index: HashMap::new(),
            });
        }

        // Read file
        let mut file =
            File::open(path).map_err(|e| Error::Storage(format!("Failed to open file: {}", e)))?;

        let mut buffer = Vec::new();
        file.read_to_end(&mut buffer)
            .map_err(|e| Error::Storage(format!("Failed to read file: {}", e)))?;

        // Deserialize from bincode
        let mut storage: Self = bincode::deserialize(&buffer)
            .map_err(|e| Error::Storage(format!("Deserialization failed: {}", e)))?;
        storage.rebuild_index();

        Ok(storage)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use axum::{
        body::{to_bytes, Body},
        http::{Method, Request, StatusCode},
    };
    use tower::ServiceExt;

    fn test_series(id: u64, labels: &[(&str, &str)], samples: &[(i64, f64)]) -> TimeSeries {
        TimeSeries {
            id: SeriesId(id),
            labels: labels
                .iter()
                .map(|(name, value)| Label::new(*name, *value))
                .collect(),
            samples: samples
                .iter()
                .map(|(timestamp, value)| Sample::new(*timestamp, *value))
                .collect(),
        }
    }

    async fn seed_series(service: &QueryService, series: Vec<TimeSeries>) {
        let mut storage = service.storage.write().await;
        for entry in series {
            storage.upsert_series(entry);
        }
    }

    #[tokio::test]
    async fn test_query_service_creation() {
        let service = QueryService::new();
        // Verify service can be created
        assert!(service.storage.read().await.series.is_empty());
    }

    #[test]
    fn test_simple_selector_parsing() {
        // Test that we can parse a simple PromQL query
        let query = "http_requests_total";
        let result = promql_parser::parser::parse(query);
        assert!(result.is_ok());
    }

    #[test]
    fn test_label_selector_parsing() {
        let query = "http_requests_total{method=\"GET\"}";
        let result = promql_parser::parser::parse(query);
        assert!(result.is_ok());
    }

    #[test]
    fn test_aggregation_parsing() {
        let query = "sum(http_requests_total)";
        let result = promql_parser::parser::parse(query);
        assert!(result.is_ok());
    }

    #[test]
    fn test_rate_function_parsing() {
        let query = "rate(http_requests_total[5m])";
        let result = promql_parser::parser::parse(query);
        assert!(result.is_ok());
    }

    #[tokio::test]
    async fn test_instant_query_empty_storage() {
        let service = QueryService::new();
        let result = service.execute_instant_query("up", 1000).await;
        assert!(result.is_ok());
        let query_result = result.unwrap();
        assert_eq!(query_result.result_type, "vector");
    }

    #[tokio::test]
    async fn test_range_query_empty_storage() {
        let service = QueryService::new();
        let result = service.execute_range_query("up", 1000, 2000, 100).await;
        assert!(result.is_ok());
    }

    #[tokio::test]
    async fn test_scalar_instant_query_returns_scalar_result() {
        let service = QueryService::new();
        let result = service.execute_instant_query("1", 1000).await.unwrap();
        assert_eq!(result.result_type, "scalar");
        assert_eq!(result.result.len(), 1);
        assert_eq!(result.result[0].value, Some((1000, 1.0)));
    }

    #[tokio::test]
    async fn test_label_matchers_support_regex_and_negative_match() {
        let service = QueryService::new();
        seed_series(
            &service,
            vec![
                test_series(
                    1,
                    &[
                        ("__name__", "http_requests_total"),
                        ("method", "GET"),
                        ("status", "200"),
                    ],
                    &[(1000, 10.0)],
                ),
                test_series(
                    2,
                    &[
                        ("__name__", "http_requests_total"),
                        ("method", "POST"),
                        ("status", "500"),
                    ],
                    &[(1000, 20.0)],
                ),
            ],
        )
        .await;

        let result = service
            .execute_instant_query("http_requests_total{method=~\"G.*\",status!=\"500\"}", 1000)
            .await
            .unwrap();

        assert_eq!(result.result_type, "vector");
        assert_eq!(result.result.len(), 1);
        assert_eq!(
            result.result[0].metric.get("method"),
            Some(&"GET".to_string())
        );
    }

    #[tokio::test]
    async fn test_aggregation_groups_by_labels() {
        let service = QueryService::new();
        seed_series(
            &service,
            vec![
                test_series(
                    1,
                    &[("__name__", "cpu_usage"), ("job", "api"), ("instance", "a")],
                    &[(1000, 2.0)],
                ),
                test_series(
                    2,
                    &[("__name__", "cpu_usage"), ("job", "api"), ("instance", "b")],
                    &[(1000, 3.0)],
                ),
            ],
        )
        .await;

        let result = service
            .execute_instant_query("sum by (job)(cpu_usage)", 1000)
            .await
            .unwrap();

        assert_eq!(result.result.len(), 1);
        assert_eq!(result.result[0].metric.get("job"), Some(&"api".to_string()));
        assert_eq!(result.result[0].value, Some((1000, 5.0)));
    }

    #[tokio::test]
    async fn test_binary_queries_support_vector_scalar_and_vector_vector() {
        let service = QueryService::new();
        seed_series(
            &service,
            vec![
                test_series(
                    1,
                    &[("__name__", "requests_total"), ("service", "api")],
                    &[(1000, 20.0)],
                ),
                test_series(
                    2,
                    &[("__name__", "errors_total"), ("service", "api")],
                    &[(1000, 5.0)],
                ),
            ],
        )
        .await;

        let vector_scalar = service
            .execute_instant_query("requests_total / 2", 1000)
            .await
            .unwrap();
        assert_eq!(vector_scalar.result.len(), 1);
        assert_eq!(
            vector_scalar.result[0].metric.get("service"),
            Some(&"api".to_string())
        );
        assert_eq!(vector_scalar.result[0].value, Some((1000, 10.0)));
        assert!(!vector_scalar.result[0].metric.contains_key("__name__"));

        let ratio = service
            .execute_instant_query("errors_total / requests_total", 1000)
            .await
            .unwrap();
        assert_eq!(ratio.result.len(), 1);
        assert_eq!(ratio.result[0].value, Some((1000, 0.25)));
        assert_eq!(ratio.result[0].metric.len(), 1);
        assert_eq!(
            ratio.result[0].metric.get("service"),
            Some(&"api".to_string())
        );
    }

    #[tokio::test]
    async fn test_histogram_quantile_with_grouped_buckets() {
        let service = QueryService::new();
        seed_series(
            &service,
            vec![
                test_series(
                    1,
                    &[
                        ("__name__", "request_duration_seconds_bucket"),
                        ("job", "api"),
                        ("instance", "a"),
                        ("le", "0.1"),
                    ],
                    &[(1000, 5.0)],
                ),
                test_series(
                    2,
                    &[
                        ("__name__", "request_duration_seconds_bucket"),
                        ("job", "api"),
                        ("instance", "a"),
                        ("le", "0.2"),
                    ],
                    &[(1000, 10.0)],
                ),
                test_series(
                    3,
                    &[
                        ("__name__", "request_duration_seconds_bucket"),
                        ("job", "api"),
                        ("instance", "a"),
                        ("le", "+Inf"),
                    ],
                    &[(1000, 20.0)],
                ),
                test_series(
                    4,
                    &[
                        ("__name__", "request_duration_seconds_bucket"),
                        ("job", "api"),
                        ("instance", "b"),
                        ("le", "0.1"),
                    ],
                    &[(1000, 5.0)],
                ),
                test_series(
                    5,
                    &[
                        ("__name__", "request_duration_seconds_bucket"),
                        ("job", "api"),
                        ("instance", "b"),
                        ("le", "0.2"),
                    ],
                    &[(1000, 10.0)],
                ),
                test_series(
                    6,
                    &[
                        ("__name__", "request_duration_seconds_bucket"),
                        ("job", "api"),
                        ("instance", "b"),
                        ("le", "+Inf"),
                    ],
                    &[(1000, 20.0)],
                ),
            ],
        )
        .await;

        let result = service
            .execute_instant_query(
                "histogram_quantile(0.5, sum by (job, le)(request_duration_seconds_bucket{job=\"api\"}))",
                1000,
            )
            .await
            .unwrap();

        assert_eq!(result.result.len(), 1);
        assert_eq!(result.result[0].metric.get("job"), Some(&"api".to_string()));
        assert!(!result.result[0].metric.contains_key("le"));
        assert_eq!(result.result[0].value, Some((1000, 0.2)));
    }

    #[tokio::test]
    async fn test_query_range_route_supports_binary_expression() {
        let service = QueryService::new();
        seed_series(
            &service,
            vec![test_series(
                1,
                &[("__name__", "requests_total"), ("service", "api")],
                &[(1000, 10.0), (2000, 20.0)],
            )],
        )
        .await;

        let app: axum::Router = service.router();
        let request = Request::builder()
            .method(Method::GET)
            .uri("/api/v1/query_range?query=requests_total%20/%202&start=1000&end=2000&step=1000")
            .body(Body::empty())
            .unwrap();
        let response = app.oneshot(request).await.unwrap();
        assert_eq!(response.status(), StatusCode::OK);

        let body = to_bytes(response.into_body(), 1024 * 1024).await.unwrap();
        let payload: serde_json::Value = serde_json::from_slice(&body).unwrap();
        assert_eq!(payload["status"], "success");
        assert_eq!(payload["data"]["resultType"], "matrix");
        assert_eq!(payload["data"]["result"][0]["metric"]["service"], "api");
        assert_eq!(
            payload["data"]["result"][0]["values"][0],
            serde_json::json!([1000, 5.0])
        );
        assert_eq!(
            payload["data"]["result"][0]["values"][1],
            serde_json::json!([2000, 10.0])
        );
    }

    #[tokio::test]
    async fn test_storage_upsert() {
        let service = QueryService::new();
        let mut storage = service.storage.write().await;

        let series = TimeSeries {
            id: SeriesId(1),
            labels: vec![
                Label::new("__name__", "test_metric"),
                Label::new("job", "test"),
            ],
            samples: vec![Sample::new(1000, 42.0)],
        };

        storage.upsert_series(series);
        assert_eq!(storage.series.len(), 1);
    }

    #[tokio::test]
    async fn test_label_values() {
        let service = QueryService::new();
        let mut storage = service.storage.write().await;

        let series = TimeSeries {
            id: SeriesId(1),
            labels: vec![
                Label::new("__name__", "test_metric"),
                Label::new("job", "test_job"),
            ],
            samples: vec![],
        };

        storage.upsert_series(series);

        let values = storage.label_values("job");
        assert_eq!(values.len(), 1);
        assert!(values.contains(&"test_job".to_string()));
    }

    #[tokio::test]
    async fn test_label_values_route() {
        let service = QueryService::new();
        {
            let mut storage = service.storage.write().await;
            storage.upsert_series(TimeSeries {
                id: SeriesId(1),
                labels: vec![
                    Label::new("__name__", "test_metric"),
                    Label::new("job", "test_job"),
                ],
                samples: vec![],
            });
        }

        let app: axum::Router = service.router();
        let request = Request::builder()
            .method(Method::GET)
            .uri("/api/v1/label/job/values")
            .body(Body::empty())
            .unwrap();
        let response = app.oneshot(request).await.unwrap();
        assert_eq!(response.status(), StatusCode::OK);

        let body = to_bytes(response.into_body(), 1024 * 1024).await.unwrap();
        let payload: serde_json::Value = serde_json::from_slice(&body).unwrap();
        assert_eq!(payload["status"], "success");
        assert!(payload["data"]
            .as_array()
            .unwrap()
            .iter()
            .any(|value| value == "test_job"));
    }

    #[tokio::test]
    async fn test_metadata_queries_support_regex_and_negative_matchers() {
        let service = QueryService::new();
        seed_series(
            &service,
            vec![
                test_series(
                    1,
                    &[
                        ("__name__", "http_requests_total"),
                        ("job", "api"),
                        ("instance", "a"),
                    ],
                    &[(1000, 1.0)],
                ),
                test_series(
                    2,
                    &[
                        ("__name__", "http_requests_total"),
                        ("job", "worker"),
                        ("instance", "b"),
                    ],
                    &[(1000, 1.0)],
                ),
            ],
        )
        .await;

        let series = service
            .series_metadata(&["job=~\"a.*|api\"".to_string()], None, None)
            .await
            .unwrap();
        assert_eq!(series.len(), 1);
        assert_eq!(series[0].get("job"), Some(&"api".to_string()));

        let values = service
            .label_values_for_matchers("instance", &["job!=\"worker\"".to_string()], None, None)
            .await
            .unwrap();
        assert_eq!(values, vec!["a".to_string()]);
    }

    #[tokio::test]
    async fn test_empty_label_matchers_treat_missing_labels_as_empty() {
        let service = QueryService::new();
        seed_series(
            &service,
            vec![test_series(
                1,
                &[("__name__", "up"), ("job", "api")],
                &[(1000, 1.0)],
            )],
        )
        .await;

        let equal_empty = service
            .execute_instant_query("up{zone=\"\"}", 1000)
            .await
            .unwrap();
        assert_eq!(equal_empty.result.len(), 1);

        let regex_empty = service
            .execute_instant_query("up{zone=~\".*\"}", 1000)
            .await
            .unwrap();
        assert_eq!(regex_empty.result.len(), 1);

        let not_equal_empty = service
            .execute_instant_query("up{zone!=\"\"}", 1000)
            .await
            .unwrap();
        assert!(not_equal_empty.result.is_empty());

        let metadata = service
            .series_metadata(&["zone=\"\"".to_string()], None, None)
            .await
            .unwrap();
        assert_eq!(metadata.len(), 1);
    }

    #[test]
    fn test_persistence_save_load_empty() {
        use tempfile::tempdir;

        // Create temporary directory
        let dir = tempdir().unwrap();
        let path = dir.path().join("test.db");

        // Create empty storage and save
        let storage = QueryableStorage {
            series: HashMap::new(),
            label_index: HashMap::new(),
        };

        storage.save_to_file(&path).unwrap();
        assert!(path.exists());

        // Load back
        let loaded = QueryableStorage::load_from_file(&path).unwrap();
        assert_eq!(loaded.series.len(), 0);
        assert_eq!(loaded.label_index.len(), 0);
    }

    #[test]
    fn test_persistence_save_load_with_data() {
        use tempfile::tempdir;

        let dir = tempdir().unwrap();
        let path = dir.path().join("test.db");

        // Create storage with data
        let mut storage = QueryableStorage {
            series: HashMap::new(),
            label_index: HashMap::new(),
        };

        let series1 = TimeSeries {
            id: SeriesId(1),
            labels: vec![Label::new("__name__", "metric1"), Label::new("job", "test")],
            samples: vec![Sample::new(1000, 10.0), Sample::new(2000, 20.0)],
        };

        let series2 = TimeSeries {
            id: SeriesId(2),
            labels: vec![Label::new("__name__", "metric2"), Label::new("job", "prod")],
            samples: vec![Sample::new(1000, 30.0)],
        };

        storage.upsert_series(series1.clone());
        storage.upsert_series(series2.clone());

        // Save to disk
        storage.save_to_file(&path).unwrap();
        assert!(path.exists());

        // Load back
        let loaded = QueryableStorage::load_from_file(&path).unwrap();
        assert_eq!(loaded.series.len(), 2);
        assert_eq!(loaded.label_index.len(), 2); // __name__ and job

        // Verify series data
        let loaded_series1 = loaded.series.get(&SeriesId(1)).unwrap();
        assert_eq!(loaded_series1.labels.len(), 2);
        assert_eq!(loaded_series1.samples.len(), 2);
        assert_eq!(loaded_series1.samples[0].value, 10.0);

        // Verify label index
        let job_values = loaded.label_values("job");
        assert_eq!(job_values.len(), 2);
        assert!(job_values.contains(&"test".to_string()));
        assert!(job_values.contains(&"prod".to_string()));
    }

    #[test]
    fn test_persistence_load_nonexistent_file() {
        use tempfile::tempdir;

        let dir = tempdir().unwrap();
        let path = dir.path().join("nonexistent.db");

        // Loading non-existent file should return empty storage
        let loaded = QueryableStorage::load_from_file(&path).unwrap();
        assert_eq!(loaded.series.len(), 0);
        assert_eq!(loaded.label_index.len(), 0);
    }

    #[tokio::test]
    async fn test_query_service_persistence() {
        use tempfile::tempdir;

        let dir = tempdir().unwrap();
        let path = dir.path().join("service_test.db");

        // Create service and add some data
        let service = QueryService::new();
        {
            let mut storage = service.storage.write().await;
            let series = TimeSeries {
                id: SeriesId(42),
                labels: vec![Label::new("__name__", "test_metric")],
                samples: vec![Sample::new(1000, 99.5)],
            };
            storage.upsert_series(series);
        }

        // Save to disk
        service.save_to_disk(&path).await.unwrap();

        // Create new service loading from disk
        let new_service = QueryService::new_with_persistence(&path).unwrap();
        let storage = new_service.storage.read().await;

        // Verify data was persisted
        assert_eq!(storage.series.len(), 1);
        let loaded_series = storage.series.get(&SeriesId(42)).unwrap();
        assert_eq!(loaded_series.samples[0].value, 99.5);
    }
}
