//! 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 parking_lot::Mutex;
use nightlight_types::{Error, Label, Result, Sample, SeriesId, TimeSeries};
use promql_parser::{
    label::Matchers,
    parser::{
        AggregateExpr, BinaryExpr, Call, Expr, MatrixSelector, VectorSelector,
    },
};
use serde::{Deserialize, Serialize};
use std::collections::{HashMap, VecDeque};
use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::Arc;
use std::time::Instant;
use tokio::sync::RwLock;
use tracing::{debug, error};
#[cfg(test)]
use tracing::info;

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,
}

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_expr(&expr, time, time, 0, &storage).await;
        let success = result.is_ok();
        self.metrics.finish_query(started, success);
        let result = result?;

        Ok(QueryResult {
            result_type: "vector".to_string(),
            result: result
                .into_iter()
                .map(|ts| {
                    let metric = ts
                        .labels
                        .into_iter()
                        .map(|l| (l.name, l.value))
                        .collect();
                    let value = ts.samples.last().map(|s| (s.timestamp, s.value));
                    InstantQueryResult { metric, value }
                })
                .collect(),
        })
    }

    /// 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_expr(&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);
                }
            };

            for ts in step_result {
                // Create a unique key for this series based on labels
                let series_key = ts
                    .labels
                    .iter()
                    .map(|l| format!("{}={}", l.name, l.value))
                    .collect::<Vec<_>>()
                    .join(",");

                // Find or create result entry for this series
                let entry = results.entry(series_key).or_insert_with(|| {
                    let metric = ts
                        .labels
                        .iter()
                        .map(|l| (l.name.clone(), l.value.clone()))
                        .collect();
                    RangeResult {
                        metric,
                        values: Vec::new(),
                    }
                });

                // Append samples to existing series
                for sample in ts.samples {
                    entry.values.push((sample.timestamp, sample.value));
                }
            }

            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_expr<'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<Vec<TimeSeries>>> + Send + 'a>> {
        Box::pin(async move {
            match expr {
                Expr::VectorSelector(selector) => {
                    // Vector selector: metric_name{label="value"}
                    self.evaluate_vector_selector(selector, time, storage)
                }
                Expr::MatrixSelector(selector) => {
                    // Range selector: metric_name[5m]
                    self.evaluate_matrix_selector(selector, time, storage)
                }
                Expr::Aggregate(agg) => {
                    // Aggregation: sum(metric), avg(metric), etc.
                    self.evaluate_aggregation(agg, time, end_time, step, storage)
                        .await
                }
                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
                }
                _ => 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_selectors(ts, &selector.matchers))
            .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_selectors(ts, &selector.vs.matchers))
            .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>> {
        // Evaluate the input expression
        let input_series = self
            .evaluate_expr(&agg.expr, time, end_time, step, storage)
            .await?;

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

        // Perform aggregation
        let aggregated_value = match agg.op.to_string().to_lowercase().as_str() {
            "sum" => input_series
                .iter()
                .flat_map(|ts| ts.samples.iter().map(|s| s.value))
                .sum(),
            "avg" => {
                let sum: f64 = input_series
                    .iter()
                    .flat_map(|ts| ts.samples.iter().map(|s| s.value))
                    .sum();
                let count = input_series
                    .iter()
                    .map(|ts| ts.samples.len())
                    .sum::<usize>() as f64;
                if count > 0.0 {
                    sum / count
                } else {
                    0.0
                }
            }
            "min" => input_series
                .iter()
                .flat_map(|ts| ts.samples.iter().map(|s| s.value))
                .fold(f64::INFINITY, f64::min),
            "max" => input_series
                .iter()
                .flat_map(|ts| ts.samples.iter().map(|s| s.value))
                .fold(f64::NEG_INFINITY, f64::max),
            "count" => input_series.len() as f64,
            op => {
                return Err(Error::Query(format!("Unsupported aggregation: {}", op)));
            }
        };

        // Create result time series
        Ok(vec![TimeSeries {
            id: SeriesId(0), // Aggregated result has no series ID
            labels: vec![Label {
                name: "__name__".to_string(),
                value: format!("{}()", agg.op),
            }],
            samples: vec![Sample {
                timestamp: time,
                value: aggregated_value,
            }],
        }])
    }

    /// 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<Vec<TimeSeries>> {
        let func_name = &call.func.name;

        match func_name.to_string().as_str() {
            "rate" => self.evaluate_rate(call, time, end_time, step, storage).await,
            "irate" => {
                self.evaluate_irate(call, time, end_time, step, storage)
                    .await
            }
            "increase" => {
                self.evaluate_increase(call, time, end_time, step, storage)
                    .await
            }
            "histogram_quantile" => {
                self.evaluate_histogram_quantile(call, time, end_time, step, storage)
                    .await
            }
            _ => 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()));
        }

        // Get the first argument - should be a MatrixSelector
        let arg = &call.args.args[0];

        // Evaluate the argument to get range data
        let series_list = Box::pin(self.evaluate_expr(arg, time, end_time, step, storage)).await?;

        // 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()));
        }

        // Get the first argument - should be a MatrixSelector
        let arg = &call.args.args[0];

        // Evaluate the argument to get range data
        let series_list = Box::pin(self.evaluate_expr(arg, time, end_time, step, storage)).await?;

        // 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()));
        }

        // Get the first argument - should be a MatrixSelector
        let arg = &call.args.args[0];

        // Evaluate the argument to get range data
        let series_list = Box::pin(self.evaluate_expr(arg, time, end_time, step, storage)).await?;

        // 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() function (simplified - stub for now)
    async fn evaluate_histogram_quantile(
        &self,
        _call: &Call,
        _time: i64,
        _end_time: i64,
        _step: i64,
        _storage: &QueryableStorage,
    ) -> Result<Vec<TimeSeries>> {
        // Simplified implementation - full histogram quantile is complex
        // This would require proper histogram bucket handling
        Err(Error::Query(
            "histogram_quantile() not yet implemented".into(),
        ))
    }

    /// Evaluate binary operation (simplified - stub for now)
    async fn evaluate_binary(
        &self,
        _binary: &BinaryExpr,
        _time: i64,
        _end_time: i64,
        _step: i64,
        _storage: &QueryableStorage,
    ) -> Result<Vec<TimeSeries>> {
        // Simplified binary operation evaluation
        // Full implementation would require proper vector matching
        Err(Error::Query(
            "Binary operations not yet fully implemented".into(),
        ))
    }

    /// Check if a time series matches label matchers
    fn matches_selectors(&self, ts: &TimeSeries, matchers: &Matchers) -> bool {
        for matcher in &matchers.matchers {
            let label_name = &matcher.name;
            let label_value = ts
                .labels
                .iter()
                .find(|l| &l.name == label_name)
                .map(|l| l.value.as_str());

            // For now, simple exact match (can be enhanced)
            let matches = if let Some(value) = label_value {
                matcher.value == value
            } else {
                false
            };

            if !matches {
                return false;
            }
        }

        true
    }

    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 result = Ok(series
            .into_iter()
            .map(|ts| {
                ts.labels
                    .iter()
                    .map(|label| (label.name.clone(), label.value.clone()))
                    .collect()
            })
            .collect());
        self.metrics.finish_query(started, true);
        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 mut values: Vec<String> = self
            .matching_series(&storage, matchers, start, end)
            .into_iter()
            .filter_map(|series| series.get_label(label_name).map(str::to_string))
            .collect();
        values.sort();
        values.dedup();
        self.metrics.finish_query(started, true);
        Ok(values)
    }

    fn matching_series(
        &self,
        storage: &QueryableStorage,
        matchers: &[String],
        start: Option<i64>,
        end: Option<i64>,
    ) -> Vec<TimeSeries> {
        let parsed_matchers = parse_label_matchers(matchers);
        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 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_label_matchers(matchers: &[String]) -> Vec<(String, String)> {
    matchers
        .iter()
        .filter_map(|matcher| matcher.split_once('='))
        .map(|(key, value)| {
            (
                key.trim().to_string(),
                value.trim().trim_matches('"').to_string(),
            )
        })
        .collect()
}

fn series_matches(series: &TimeSeries, matchers: &[(String, String)]) -> bool {
    matchers.iter().all(|(key, value)| {
        series
            .labels
            .iter()
            .any(|label| &label.name == key && &label.value == 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;

    #[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_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"));
    }

    #[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);
    }
}
