/*-------------------------------------------------------------------------
 * Copyright (c) Microsoft Corporation.  All rights reserved.
 *
 * documentdb_gateway_core/src/explain/model.rs
 *
 *-------------------------------------------------------------------------
 */

use serde::Deserialize;

#[derive(Deserialize, Debug, Clone)]
#[serde(rename_all = "PascalCase")]
pub struct DistributedTask {
    #[serde(rename = "Node")]
    pub _node: String,

    #[serde(rename = "Remote Plan")]
    pub worker_plans: Vec<Vec<PostgresExplain>>,

    #[serde(rename = "Query")]
    pub _query: String,

    pub error: Option<String>,
}

#[derive(Deserialize, Debug, Clone)]
#[serde(rename_all = "PascalCase")]
pub struct DistributedJob {
    #[serde(rename = "Task Count")]
    pub task_count: i32,

    #[serde(rename = "Tasks Shown")]
    pub tasks_shown: String,

    #[serde(rename = "Tuple data received from nodes")]
    pub total_response_size: Option<String>,

    pub tasks: Vec<DistributedTask>,
}

#[derive(Deserialize, Debug, Clone)]
pub struct DistributedSubPlan {
    #[serde(rename = "PlannedStmt")]
    pub statements: Vec<PostgresExplain>,
}

#[derive(Deserialize, Debug, Clone)]
#[serde(rename_all = "PascalCase")]
pub struct DistributedQueryPlan {
    pub job: DistributedJob,
    pub subplans: Option<Vec<DistributedSubPlan>>,
}

#[derive(Deserialize, Debug, Clone)]
#[serde(rename_all = "PascalCase")]
pub struct PostgresExplain {
    pub plan: ExplainPlan,

    #[serde(rename = "Planning Time")]
    pub planning_time: Option<f64>,

    #[serde(rename = "Execution Time")]
    pub execution_time: Option<f64>,
}

#[derive(Deserialize, Debug, Clone, Default)]
#[serde(rename_all = "PascalCase")]
pub struct ExplainPlan {
    #[serde(rename = "Actual Rows")]
    pub actual_rows: Option<i64>,

    #[serde(rename = "Actual Total Time")]
    pub actual_total_time: Option<f64>,

    #[serde(rename = "Actual Startup Time")]
    pub actual_startup_time: Option<f64>,

    #[serde(rename = "Alias")]
    pub alias: Option<String>,

    #[serde(rename = "Custom Plan Provider")]
    pub custom_plan_provider: Option<String>,

    #[serde(rename = "Distributed Query")]
    pub distributed_plan: Option<DistributedQueryPlan>,

    pub filter: Option<String>,

    #[serde(rename = "Group Key")]
    pub group_key: Option<Vec<String>>,

    #[serde(rename = "Heap Fetches")]
    pub heap_fetches: Option<i64>,

    #[serde(rename = "Index Cond")]
    pub index_condition: Option<String>,

    #[serde(rename = "Index Name")]
    pub index_name: Option<String>,

    #[serde(rename = "CosmosSearch Custom Params")]
    pub vector_search_custom_params: Option<String>,

    #[serde(rename = "Join Type")]
    pub join_type: Option<String>,

    #[serde(rename = "Node Type")]
    pub node_type: String,

    #[serde(rename = "Order By")]
    pub order_by: Option<String>,

    pub output: Option<Vec<String>>,

    #[serde(rename = "Relation Name")]
    pub relation_name: Option<String>,

    #[serde(rename = "Page Size")]
    pub page_size: Option<i64>,

    #[serde(rename = "Sample Size")]
    pub sample_size: Option<i64>,

    #[serde(rename = "Sample Reservoir Method")]
    pub sample_reservoir_method: Option<String>,

    #[serde(rename = "Sample Rows Skipped")]
    pub sample_rows_skipped: Option<i64>,

    #[serde(rename = "Sample Heap Fetches")]
    pub sample_heap_fetches: Option<i64>,

    #[serde(rename = "Plan Rows")]
    pub plan_rows: Option<serde_json::value::Number>,

    #[serde(rename = "Plans")]
    pub inner_plans: Option<Vec<Self>>,

    #[serde(rename = "Parent Relationship")]
    pub parent_relationship: Option<String>,

    #[serde(rename = "Rows Removed by Filter")]
    pub rows_removed_by_filter: Option<i64>,

    #[serde(rename = "Rows Removed by Index Recheck")]
    pub rows_removed_by_index: Option<i64>,

    #[serde(rename = "Scan Direction")]
    pub scan_direction: Option<String>,

    #[serde(rename = "Sort Key")]
    pub sort_keys: Option<Vec<String>>,

    #[serde(rename = "Presorted Key")]
    pub presorted_key: Option<Vec<String>>,

    #[serde(rename = "Sort Method")]
    pub sort_method: Option<String>,

    #[serde(rename = "Sort Space Type")]
    pub sort_space_type: Option<String>,

    #[serde(rename = "Sort Space Used")]
    pub sort_space_used: Option<i64>,

    #[serde(rename = "Startup Cost")]
    pub startup_cost: Option<f64>,

    #[serde(rename = "Total Cost")]
    pub total_cost: Option<f64>,

    #[serde(rename = "Function Name")]
    pub function_name: Option<String>,

    #[serde(rename = "Exact Heap Blocks")]
    pub exact_heap_blocks: Option<i64>,

    #[serde(rename = "Lossy Heap Blocks")]
    pub lossy_heap_blocks: Option<i64>,

    #[serde(rename = "Shared Hit Blocks")]
    pub shared_hit_blocks: Option<i64>,

    #[serde(rename = "Shared Read Blocks")]
    pub shared_read_blocks: Option<i64>,

    #[serde(rename = "I/O Read Time")]
    pub io_read_time: Option<i64>,

    #[serde(rename = "Workers Launched")]
    pub workers_launched: Option<i64>,

    #[serde(rename = "Workers Planned")]
    pub workers_planned: Option<i64>,

    #[serde(rename = "Strategy")]
    pub strategy: Option<String>,

    #[serde(rename = "IndexDetails")]
    pub index_details: Option<Vec<IndexDetails>>,

    #[serde(rename = "IndexCosts")]
    pub index_costs: Option<Vec<IndexCost>>,

    #[serde(rename = "namespaceName")]
    pub namespace_name: Option<String>,

    /// The cursor scan strategy (e.g. "streaming", "Secondary Index Scan").
    /// Emitted in the queryPlanner stage of the wire-protocol explain output.
    #[serde(rename = "cursorScanType")]
    pub cursor_scan_type: Option<String>,

    /// Number of tuples skipped during cursor continuation resume.
    /// Emitted in the executionStats stage when > 0.
    #[serde(rename = "Skipped Tuples")]
    pub skipped_tuples: Option<f64>,
}

#[derive(Deserialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
pub struct IndexCost {
    pub index_name: Option<String>,
    pub startup_cost: Option<f64>,
    pub total_cost: Option<f64>,
    pub selectivity: Option<f64>,
    pub correlation: Option<f64>,
    pub estimated_percent_index_pages_loaded: Option<f64>,
    pub estimated_total_index_entries: Option<i64>,
    pub boundary_selectivity: Option<f64>,
    pub estimated_data_pages_loaded_percent: Option<f64>,
    pub num_boundaries: Option<i64>,
}

#[derive(Deserialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
pub struct VectorSearchParams {
    pub n_probes: Option<f64>,
    pub ef_search: Option<f64>,
    pub l_search: Option<f64>,
}

#[derive(Deserialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
pub struct IndexDetails {
    pub index_name: Option<String>,
    pub index_key: Option<String>,
    pub is_multi_key: Option<bool>,
    pub multi_key_paths: Option<Vec<String>>,
    pub has_truncation: Option<bool>,
    pub truncated_paths: Option<Vec<String>>,
    pub index_bounds: Option<Vec<String>>,
    pub raw_bounds: Option<Vec<String>>,
    pub start_bounds: Option<Vec<String>>,
    pub inner_scan_loops: Option<i64>,
    pub dead_entries_or_pages_skipped: Option<i64>,
    pub eligible_dead_items: Option<i64>,
    pub parallel_scan_capable: Option<bool>,
    pub scan_key_details: Option<Vec<String>>,
    pub scan_type: Option<String>,
    pub num_duplicates: Option<i64>,
    pub is_backward_scan: Option<bool>,
    pub has_correlated_terms: Option<bool>,
}
