// Clippy configuration - allow some lints that are too strict for this codebase
// too_many_arguments: Many rendering functions require multiple parameters for
// flexibility. Consider config structs for future additions, but current API is ergonomic.
#![allow(clippy::too_many_arguments)]
#![allow(unconditional_recursion)]
// Allow unused code during development
#![allow(dead_code)]
#![allow(unused_variables)]
#![allow(unused_imports)]
#![allow(unused_mut)]
#![allow(unreachable_code)]
#![allow(unreachable_patterns)]
#![cfg_attr(docsrs, feature(doc_cfg))]

//! # Ruviz - High-Performance Rust Plotting Library
//!
//! A modern, high-performance 2D plotting library for Rust that combines matplotlib's
//! comprehensiveness with Makie's performance-oriented design, while maintaining Rust's
//! safety and ergonomics.
//!
//! ## Features
//!
//! - **High Performance**: <100ms for 100K points, <1s for 1M points
//! - **Zero Unsafe Public API**: Memory safety without compromising performance
//! - **30+ Plotting Primitives and Layouts**: Distribution, categorical, polar, regression, and layout helpers
//! - **Publication Quality**: PNG/SVG export with custom themes
//! - **Large Dataset Support**: DataShader-style aggregation for 100M+ points
//! - **Cross Platform**: Linux, macOS, Windows
//! - **Animation Tooling**: Frame-based recording plus signal-aware plot data APIs
//!
//! ## Quick Start
//!
//! Create plots with minimal boilerplate using top-level convenience functions:
//!
//! ```rust,no_run
//! use ruviz::prelude::*;
//!
//! // Line plot - one line of code!
//! let x: Vec<f64> = (0..100).map(|i| i as f64 * 0.1).collect();
//! let y: Vec<f64> = x.iter().map(|&v| v.sin()).collect();
//! line(&x, &y).title("Sine Wave").save("sine.png")?;
//!
//! // Scatter plot
//! scatter(&x, &y).title("Points").marker(MarkerStyle::Circle).save("scatter.png")?;
//!
//! // Bar chart
//! let cats = ["A", "B", "C", "D"];
//! let vals = [10.0, 25.0, 15.0, 30.0];
//! bar(&cats, &vals).title("Sales").save("bar.png")?;
//! # Ok::<(), Box<dyn std::error::Error>>(())
//! ```
//!
//! ## Typst Text Mode
//!
//! Enable Typst-backed labels and titles by turning on the `typst-math` feature:
//!
//! ```toml
//! [dependencies]
//! ruviz = { version = "0.4.0", features = ["typst-math"] }
//! ```
//!
//! Then opt into Typst text rendering per plot with `.typst(true)`:
//!
//! ```rust,no_run
//! use ruviz::prelude::*;
//!
//! let x: Vec<f64> = (0..50).map(|i| i as f64 * 0.1).collect();
//! let y: Vec<f64> = x.iter().map(|&v| (-v).exp()).collect();
//!
//! let mut plot = Plot::new()
//!     .line(&x, &y)
//!     .title("$f(x) = e^(-x)$")
//!     .xlabel("$x$")
//!     .ylabel("$f(x)$");
//!
//! #[cfg(feature = "typst-math")]
//! {
//!     plot = plot.typst(true);
//! }
//!
//! plot.save("typst_plot.png")?;
//! # Ok::<(), Box<dyn std::error::Error>>(())
//! ```
//!
//! If `typst-math` is not enabled, `.typst(true)` is unavailable and the compiler reports:
//!
//! ```text
//! error[E0599]: no method named `typst` found for struct `ruviz::core::Plot` in the current scope
//! ```
//!
//! If Typst is optional in your own crate, define a local feature and forward it to
//! `ruviz/typst-math`:
//!
//! ```toml
//! [dependencies]
//! ruviz = { version = "0.4.0", default-features = false }
//!
//! [features]
//! default = []
//! typst-math = ["ruviz/typst-math"]
//! ```
//!
//! Then guard the call with `#[cfg(feature = "typst-math")]` in your crate. Selecting the text
//! engine directly follows the same rule: `TextEngineMode::Typst` is only available when
//! `typst-math` is enabled.
//!
//! ## Animation APIs
//!
//! Create smooth animations with `record!` closures today. Signal-backed plot data
//! and labels can also be attached to a plot. Plain `render()` and `save()`
//! sample temporal sources at `0.0`, while `render_at()` lets you choose the
//! sampling time before using the normal backend-selection path. Push-based
//! reactive sources use their latest value when the plot snapshot is built.
//!
//! ### Basic Animation with record! Macro
//!
//! ```rust,ignore
//! use ruviz::prelude::*;
//! use ruviz::record;
//!
//! // Frame-based animation
//! record!("wave.gif", 60, |t| {
//!     let phase = t.time * 2.0 * std::f64::consts::PI;
//!     let x: Vec<f64> = (0..100).map(|i| i as f64 * 0.1).collect();
//!     let y: Vec<f64> = x.iter().map(|&xi| (xi + phase).sin()).collect();
//!     line(&x, &y).title(format!("t = {:.2}s", t.time))
//! })?;
//!
//! // Duration-based animation (2 seconds at 30fps)
//! record!("bounce.gif", 2 secs, |t| {
//!     let y = t.ease_over(easing::ease_out_bounce, 100.0, 0.0, 2.0);
//!     scatter(&[0.0], &[y]).title("Bouncing Ball")
//! })?;
//!
//! // Custom framerate
//! record!("smooth.gif", 3 secs @ 60 fps, |t| {
//!     let x = t.lerp_over(0.0, 10.0, 3.0);
//!     line(&[0.0, x], &[0.0, x]).title("Growing Line")
//! })?;
//! ```
//!
//! ### Signals Inside Animation Closures
//!
//! Use `Signal<T>` to build time-varying values, then sample them inside
//! `record!` closures for animated series data today:
//!
//! ```rust,ignore
//! use ruviz::prelude::*;
//! use ruviz::animation::signal;
//! use ruviz::record;
//!
//! // Create signals that vary over time
//! let amplitude = signal::lerp(0.0, 2.0, 3.0);  // 0 to 2 over 3 seconds
//! let frequency = signal::ease(easing::ease_in_out_quad, 1.0, 5.0, 3.0);
//!
//! // Compose signals
//! let x: Vec<f64> = (0..100).map(|i| i as f64 * 0.1).collect();
//! let y_signal = signal::of(move |t| {
//!     let amp = amplitude.at(t);
//!     let freq = frequency.at(t);
//!     (0..100).map(|i| {
//!         let x = i as f64 * 0.1;
//!         amp * (x * freq).sin()
//!     }).collect::<Vec<f64>>()
//! });
//!
//! // Use a signal-backed title alongside the sampled series data
//! let title = signal::of(|t| format!("Wave Animation - t={:.2}s", t));
//!
//! record!("wave.gif", 3 secs, |t| {
//!     let y = y_signal.at(t);
//!     Plot::new()
//!         .title(title.at(t))
//!         .line(&x, &y)
//! })?;
//! ```
//!
//! ### Reactive Labels
//!
//! Attach signal-backed titles and axis labels:
//!
//! ```rust,ignore
//! use ruviz::prelude::*;
//! use ruviz::animation::signal;
//!
//! // Dynamic title showing current time
//! let title = signal::of(|t| format!("Simulation: {:.1}s", t));
//!
//! // Dynamic axis label
//! let ylabel = signal::of(|t| {
//!     if t < 1.0 { "Accelerating".to_string() }
//!     else if t < 2.0 { "Constant Velocity".to_string() }
//!     else { "Decelerating".to_string() }
//! });
//!
//! let x: Vec<f64> = (0..100).map(|i| i as f64 * 0.1).collect();
//! let y: Vec<f64> = x.iter().map(|&xi| xi.sin()).collect();
//!
//! let plot = Plot::new()
//!     .title_signal(title)
//!     .xlabel("Time")
//!     .ylabel_signal(ylabel)
//!     .line(&x, &y);
//! ```
//!
//! ### Signal Composition
//!
//! Combine multiple signals for complex animations:
//!
//! ```rust,ignore
//! use ruviz::animation::signal;
//!
//! // Basic signal constructors
//! let constant = signal::constant(42.0);           // Always returns 42
//! let time = signal::time();                       // Returns current time
//! let linear = signal::lerp(0.0, 100.0, 2.0);     // Linear interpolation
//! let eased = signal::ease(easing::ease_out_bounce, 100.0, 0.0, 2.0);
//!
//! // Transform signals
//! let doubled = linear.map(|v| v * 2.0);
//!
//! // Combine two signals
//! let combined = signal::zip(linear.clone(), eased, |a, b| a + b);
//!
//! // Combine three signals
//! let rgb = signal::zip3(
//!     signal::lerp(0.0, 255.0, 1.0),
//!     signal::lerp(255.0, 0.0, 1.0),
//!     signal::constant(128.0),
//!     |r, g, b| (r as u8, g as u8, b as u8)
//! );
//!
//! // Custom signal from closure
//! let sine_wave = signal::of(|t| (t * std::f64::consts::TAU).sin());
//! ```
//!
//! ## Gallery
//!
//! Click any image to view full size. Expand sections below to see code examples.
//!
//! ### Plot Types
//!
//! | | | |
//! |:---:|:---:|:---:|
//! | <a href="https://raw.githubusercontent.com/Ameyanagi/ruviz/main/docs/assets/rustdoc/line_plot.png"><img src="https://raw.githubusercontent.com/Ameyanagi/ruviz/main/docs/assets/rustdoc/line_plot.png" width="250"></a> | <a href="https://raw.githubusercontent.com/Ameyanagi/ruviz/main/docs/assets/rustdoc/scatter_plot.png"><img src="https://raw.githubusercontent.com/Ameyanagi/ruviz/main/docs/assets/rustdoc/scatter_plot.png" width="250"></a> | <a href="https://raw.githubusercontent.com/Ameyanagi/ruviz/main/docs/assets/rustdoc/bar_chart.png"><img src="https://raw.githubusercontent.com/Ameyanagi/ruviz/main/docs/assets/rustdoc/bar_chart.png" width="250"></a> |
//! | Line Plot | Scatter Plot | Bar Chart |
//! | <a href="https://raw.githubusercontent.com/Ameyanagi/ruviz/main/docs/assets/rustdoc/histogram.png"><img src="https://raw.githubusercontent.com/Ameyanagi/ruviz/main/docs/assets/rustdoc/histogram.png" width="250"></a> | <a href="https://raw.githubusercontent.com/Ameyanagi/ruviz/main/docs/assets/rustdoc/boxplot.png"><img src="https://raw.githubusercontent.com/Ameyanagi/ruviz/main/docs/assets/rustdoc/boxplot.png" width="250"></a> | <a href="https://raw.githubusercontent.com/Ameyanagi/ruviz/main/docs/assets/rustdoc/heatmap.png"><img src="https://raw.githubusercontent.com/Ameyanagi/ruviz/main/docs/assets/rustdoc/heatmap.png" width="250"></a> |
//! | Histogram | Box Plot | Heatmap |
//! | <a href="https://raw.githubusercontent.com/Ameyanagi/ruviz/main/docs/assets/rustdoc/kde_plot.png"><img src="https://raw.githubusercontent.com/Ameyanagi/ruviz/main/docs/assets/rustdoc/kde_plot.png" width="250"></a> | <a href="https://raw.githubusercontent.com/Ameyanagi/ruviz/main/docs/assets/rustdoc/ecdf_plot.png"><img src="https://raw.githubusercontent.com/Ameyanagi/ruviz/main/docs/assets/rustdoc/ecdf_plot.png" width="250"></a> | <a href="https://raw.githubusercontent.com/Ameyanagi/ruviz/main/docs/assets/rustdoc/pie_chart.png"><img src="https://raw.githubusercontent.com/Ameyanagi/ruviz/main/docs/assets/rustdoc/pie_chart.png" width="250"></a> |
//! | KDE Plot | ECDF Plot | Pie Chart |
//! | <a href="https://raw.githubusercontent.com/Ameyanagi/ruviz/main/docs/assets/rustdoc/errorbar_plot.png"><img src="https://raw.githubusercontent.com/Ameyanagi/ruviz/main/docs/assets/rustdoc/errorbar_plot.png" width="250"></a> | <a href="https://raw.githubusercontent.com/Ameyanagi/ruviz/main/docs/assets/rustdoc/violin_plot.png"><img src="https://raw.githubusercontent.com/Ameyanagi/ruviz/main/docs/assets/rustdoc/violin_plot.png" width="250"></a> | <a href="https://raw.githubusercontent.com/Ameyanagi/ruviz/main/docs/assets/rustdoc/contour_plot.png"><img src="https://raw.githubusercontent.com/Ameyanagi/ruviz/main/docs/assets/rustdoc/contour_plot.png" width="250"></a> |
//! | Error Bar | Violin Plot | Contour Plot |
//! | <a href="https://raw.githubusercontent.com/Ameyanagi/ruviz/main/docs/assets/rustdoc/polar_plot.png"><img src="https://raw.githubusercontent.com/Ameyanagi/ruviz/main/docs/assets/rustdoc/polar_plot.png" width="250"></a> | <a href="https://raw.githubusercontent.com/Ameyanagi/ruviz/main/docs/assets/rustdoc/radar_chart.png"><img src="https://raw.githubusercontent.com/Ameyanagi/ruviz/main/docs/assets/rustdoc/radar_chart.png" width="250"></a> | |
//! | Polar Plot | Radar Chart | |
//!
//! ### Additional Plot Types
//!
//! The top-level [`Plot`] builder covers the most common scientific chart types:
//!
//! | Category | Plot Types |
//! |----------|------------|
//! | **Basic** | Line, Scatter, Bar |
//! | **Distribution** | Histogram, Box Plot, Violin, KDE, ECDF |
//! | **Continuous** | Heatmap, Contour, Fill Between |
//! | **Error** | Error Bars |
//! | **Composition** | Pie |
//! | **Polar** | Polar Plot, Radar/Spider Chart |
//!
//! Lower-level utilities in [`plots`] expose additional configs and computation
//! helpers for specialized workflows. See the [Plot Types Guide](https://github.com/Ameyanagi/ruviz/blob/main/docs/guide/04_plot_types.md)
//! for current coverage details.
//!
//! <details>
//! <summary>Plot Types Code Examples</summary>
//!
//! **Line Plot**
//! ```rust,no_run
//! use ruviz::prelude::*;
//!
//! let x: Vec<f64> = (0..100).map(|i| i as f64 * 0.1).collect();
//! let y: Vec<f64> = x.iter().map(|&v| v.sin()).collect();
//!
//! Plot::new()
//!     .title("Sine Wave")
//!     .xlabel("x")
//!     .ylabel("sin(x)")
//!     .line(&x, &y)
//!     .end_series()
//!     .save("line_plot.png")?;
//! # Ok::<(), Box<dyn std::error::Error>>(())
//! ```
//!
//! **Scatter Plot**
//! ```rust,no_run
//! use ruviz::prelude::*;
//!
//! let x: Vec<f64> = (0..50).map(|i| i as f64 * 0.2).collect();
//! let y: Vec<f64> = x.iter().enumerate()
//!     .map(|(i, &v)| v.sin() + (i as f64 * 0.1).sin() * 0.3)
//!     .collect();
//!
//! Plot::new()
//!     .title("Scatter Plot")
//!     .xlabel("x")
//!     .ylabel("y")
//!     .scatter(&x, &y)
//!     .end_series()
//!     .save("scatter_plot.png")?;
//! # Ok::<(), Box<dyn std::error::Error>>(())
//! ```
//!
//! **Bar Chart**
//! ```rust,no_run
//! use ruviz::prelude::*;
//!
//! let categories = vec!["A", "B", "C", "D", "E"];
//! let values = vec![23.0, 45.0, 56.0, 78.0, 32.0];
//!
//! Plot::new()
//!     .title("Bar Chart")
//!     .xlabel("Category")
//!     .ylabel("Value")
//!     .bar(&categories, &values)
//!     .end_series()
//!     .save("bar_chart.png")?;
//! # Ok::<(), Box<dyn std::error::Error>>(())
//! ```
//!
//! **Histogram**
//! ```rust,no_run
//! use ruviz::prelude::*;
//!
//! // Generate sample data
//! let data: Vec<f64> = (0..1000).map(|i| {
//!     let u1 = ((i * 7 + 13) % 1000) as f64 / 1000.0;
//!     let u2 = ((i * 11 + 17) % 1000) as f64 / 1000.0;
//!     (-2.0 * u1.max(0.001).ln()).sqrt() * (2.0 * std::f64::consts::PI * u2).cos()
//! }).collect();
//!
//! Plot::new()
//!     .title("Histogram")
//!     .xlabel("Value")
//!     .ylabel("Frequency")
//!     .histogram(&data, None)
//!     .end_series()
//!     .save("histogram.png")?;
//! # Ok::<(), Box<dyn std::error::Error>>(())
//! ```
//!
//! **Box Plot**
//! ```rust,no_run
//! use ruviz::prelude::*;
//! use ruviz::plots::boxplot::BoxPlotConfig;
//!
//! let data = vec![
//!     1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0,
//!     11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0,
//!     35.0, 40.0, -5.0,  // Outliers
//! ];
//!
//! Plot::new()
//!     .title("Box Plot")
//!     .xlabel("Distribution")
//!     .ylabel("Values")
//!     .boxplot(&data, Some(BoxPlotConfig::new()))
//!     .end_series()
//!     .save("boxplot.png")?;
//! # Ok::<(), Box<dyn std::error::Error>>(())
//! ```
//!
//! **Heatmap**
//! ```rust,no_run
//! use ruviz::prelude::*;
//!
//! // Create 2D data (distance from center, shifted positive for log scaling)
//! let data: Vec<Vec<f64>> = (0..10).map(|i| {
//!     (0..10).map(|j| {
//!         ((i as f64 - 5.0).powi(2) + (j as f64 - 5.0).powi(2)).sqrt() + 1.0
//!     }).collect()
//! }).collect();
//!
//! let config = HeatmapConfig::new()
//!     .value_scale(AxisScale::Log)
//!     .colorbar_label("Distance");
//!
//! Plot::new()
//!     .title("Log-Scaled Heatmap")
//!     .xlabel("X")
//!     .ylabel("Y")
//!     .heatmap(&data, Some(config))
//!     .end_series()
//!     .save("heatmap.png")?;
//! # Ok::<(), Box<dyn std::error::Error>>(())
//! ```
//!
//! </details>
//!
//! ### Styling Options
//!
//! | | | |
//! |:---:|:---:|:---:|
//! | <a href="https://raw.githubusercontent.com/Ameyanagi/ruviz/main/docs/assets/rustdoc/line_styles.png"><img src="https://raw.githubusercontent.com/Ameyanagi/ruviz/main/docs/assets/rustdoc/line_styles.png" width="250"></a> | <a href="https://raw.githubusercontent.com/Ameyanagi/ruviz/main/docs/assets/rustdoc/marker_styles.png"><img src="https://raw.githubusercontent.com/Ameyanagi/ruviz/main/docs/assets/rustdoc/marker_styles.png" width="250"></a> | <a href="https://raw.githubusercontent.com/Ameyanagi/ruviz/main/docs/assets/rustdoc/colors.png"><img src="https://raw.githubusercontent.com/Ameyanagi/ruviz/main/docs/assets/rustdoc/colors.png" width="250"></a> |
//! | Line Styles | Marker Styles | Color Palette |
//!
//! <details>
//! <summary>Styling Code Examples</summary>
//!
//! **Line Styles**
//! ```rust,no_run
//! use ruviz::prelude::*;
//!
//! let x: Vec<f64> = (0..100).map(|i| i as f64 * 0.1).collect();
//!
//! Plot::new()
//!     .title("Line Styles")
//!     .legend_position(LegendPosition::Best)
//!     .line(&x, &x.iter().map(|&v| v.sin() + 4.0).collect::<Vec<_>>())
//!     .label("Solid").style(LineStyle::Solid)
//!     .line(&x, &x.iter().map(|&v| v.sin() + 3.0).collect::<Vec<_>>())
//!     .label("Dashed").style(LineStyle::Dashed)
//!     .line(&x, &x.iter().map(|&v| v.sin() + 2.0).collect::<Vec<_>>())
//!     .label("Dotted").style(LineStyle::Dotted)
//!     .line(&x, &x.iter().map(|&v| v.sin() + 1.0).collect::<Vec<_>>())
//!     .label("DashDot").style(LineStyle::DashDot)
//!     .end_series()
//!     .save("line_styles.png")?;
//! # Ok::<(), Box<dyn std::error::Error>>(())
//! ```
//!
//! **Marker Styles**
//! ```rust,no_run
//! use ruviz::prelude::*;
//!
//! let x: Vec<f64> = (0..5).map(|j| j as f64 * 2.0).collect();
//!
//! Plot::new()
//!     .title("Marker Styles")
//!     .legend_position(LegendPosition::Best)
//!     .scatter(&x, &vec![5.0; 5]).label("Circle").marker(MarkerStyle::Circle)
//!     .scatter(&x, &vec![4.0; 5]).label("Square").marker(MarkerStyle::Square)
//!     .scatter(&x, &vec![3.0; 5]).label("Triangle").marker(MarkerStyle::Triangle)
//!     .scatter(&x, &vec![2.0; 5]).label("Diamond").marker(MarkerStyle::Diamond)
//!     .scatter(&x, &vec![1.0; 5]).label("Star").marker(MarkerStyle::Star)
//!     .end_series()
//!     .save("marker_styles.png")?;
//! # Ok::<(), Box<dyn std::error::Error>>(())
//! ```
//!
//! **Color Palette**
//! ```rust,no_run
//! use ruviz::prelude::*;
//!
//! let palette = Color::default_palette();
//! let x: Vec<f64> = (0..100).map(|i| i as f64 * 0.1).collect();
//!
//! Plot::new()
//!     .title("Default Color Palette")
//!     .legend_position(LegendPosition::Best)
//!     .line(&x, &x.iter().map(|&v| v.sin() + 3.0).collect::<Vec<_>>())
//!     .label("Color 1").color(palette[0])
//!     .line(&x, &x.iter().map(|&v| v.sin() + 2.0).collect::<Vec<_>>())
//!     .label("Color 2").color(palette[1])
//!     .line(&x, &x.iter().map(|&v| v.sin() + 1.0).collect::<Vec<_>>())
//!     .label("Color 3").color(palette[2])
//!     .line(&x, &x.iter().map(|&v| v.sin()).collect::<Vec<_>>())
//!     .label("Color 4").color(palette[3])
//!     .end_series()
//!     .save("colors.png")?;
//! # Ok::<(), Box<dyn std::error::Error>>(())
//! ```
//!
//! </details>
//!
//! ### Themes
//!
//! | | | | |
//! |:---:|:---:|:---:|:---:|
//! | <a href="https://raw.githubusercontent.com/Ameyanagi/ruviz/main/docs/assets/rustdoc/theme_default.png"><img src="https://raw.githubusercontent.com/Ameyanagi/ruviz/main/docs/assets/rustdoc/theme_default.png" width="200"></a> | <a href="https://raw.githubusercontent.com/Ameyanagi/ruviz/main/docs/assets/rustdoc/theme_dark.png"><img src="https://raw.githubusercontent.com/Ameyanagi/ruviz/main/docs/assets/rustdoc/theme_dark.png" width="200"></a> | <a href="https://raw.githubusercontent.com/Ameyanagi/ruviz/main/docs/assets/rustdoc/theme_seaborn.png"><img src="https://raw.githubusercontent.com/Ameyanagi/ruviz/main/docs/assets/rustdoc/theme_seaborn.png" width="200"></a> | <a href="https://raw.githubusercontent.com/Ameyanagi/ruviz/main/docs/assets/rustdoc/theme_publication.png"><img src="https://raw.githubusercontent.com/Ameyanagi/ruviz/main/docs/assets/rustdoc/theme_publication.png" width="200"></a> |
//! | Default | Dark | Seaborn | Publication |
//!
//! <details>
//! <summary>Themes Code Examples</summary>
//!
//! **Default Theme**
//! ```rust,no_run
//! use ruviz::prelude::*;
//!
//! let x: Vec<f64> = (0..100).map(|i| i as f64 * 0.1).collect();
//! let y: Vec<f64> = x.iter().map(|&v| v.sin()).collect();
//!
//! Plot::new()
//!     .title("Default Theme")
//!     .line(&x, &y)
//!     .end_series()
//!     .save("theme_default.png")?;
//! # Ok::<(), Box<dyn std::error::Error>>(())
//! ```
//!
//! **Dark Theme**
//! ```rust,no_run
//! use ruviz::prelude::*;
//!
//! let x: Vec<f64> = (0..100).map(|i| i as f64 * 0.1).collect();
//! let y: Vec<f64> = x.iter().map(|&v| v.sin()).collect();
//!
//! Plot::new()
//!     .title("Dark Theme")
//!     .theme(Theme::dark())
//!     .line(&x, &y)
//!     .end_series()
//!     .save("theme_dark.png")?;
//! # Ok::<(), Box<dyn std::error::Error>>(())
//! ```
//!
//! **Seaborn Theme**
//! ```rust,no_run
//! use ruviz::prelude::*;
//!
//! let x: Vec<f64> = (0..100).map(|i| i as f64 * 0.1).collect();
//! let y: Vec<f64> = x.iter().map(|&v| v.sin()).collect();
//!
//! Plot::new()
//!     .title("Seaborn Theme")
//!     .theme(Theme::seaborn())
//!     .line(&x, &y)
//!     .end_series()
//!     .save("theme_seaborn.png")?;
//! # Ok::<(), Box<dyn std::error::Error>>(())
//! ```
//!
//! **Publication Theme**
//! ```rust,no_run
//! use ruviz::prelude::*;
//!
//! let x: Vec<f64> = (0..100).map(|i| i as f64 * 0.1).collect();
//! let y: Vec<f64> = x.iter().map(|&v| v.sin()).collect();
//!
//! Plot::new()
//!     .title("Publication Theme")
//!     .theme(Theme::publication())
//!     .line(&x, &y)
//!     .end_series()
//!     .save("theme_publication.png")?;
//! # Ok::<(), Box<dyn std::error::Error>>(())
//! ```
//!
//! </details>
//!
//! ### Layout
//!
//! | | |
//! |:---:|:---:|
//! | <a href="https://raw.githubusercontent.com/Ameyanagi/ruviz/main/docs/assets/rustdoc/legend_positions.png"><img src="https://raw.githubusercontent.com/Ameyanagi/ruviz/main/docs/assets/rustdoc/legend_positions.png" width="350"></a> | <a href="https://raw.githubusercontent.com/Ameyanagi/ruviz/main/docs/assets/rustdoc/subplots.png"><img src="https://raw.githubusercontent.com/Ameyanagi/ruviz/main/docs/assets/rustdoc/subplots.png" width="350"></a> |
//! | Legend Positions | Subplots |
//!
//! <details>
//! <summary>Layout Code Examples</summary>
//!
//! **Legend Positions**
//! ```rust,no_run
//! use ruviz::prelude::*;
//!
//! let x: Vec<f64> = (0..50).map(|i| i as f64 * 0.1).collect();
//! let y_sin: Vec<f64> = x.iter().map(|&v| v.sin()).collect();
//! let y_cos: Vec<f64> = x.iter().map(|&v| v.cos()).collect();
//!
//! // Create plots with different legend positions
//! let plot_ul = Plot::new()
//!     .title("UpperLeft")
//!     .legend_position(LegendPosition::UpperLeft)
//!     .line(&x, &y_sin).label("sin(x)")
//!     .line(&x, &y_cos).label("cos(x)")
//!     .end_series();
//!
//! let plot_ur = Plot::new()
//!     .title("UpperRight")
//!     .legend_position(LegendPosition::UpperRight)
//!     .line(&x, &y_sin).label("sin(x)")
//!     .line(&x, &y_cos).label("cos(x)")
//!     .end_series();
//!
//! let plot_ll = Plot::new()
//!     .title("LowerLeft")
//!     .legend_position(LegendPosition::LowerLeft)
//!     .line(&x, &y_sin).label("sin(x)")
//!     .line(&x, &y_cos).label("cos(x)")
//!     .end_series();
//!
//! let plot_lr = Plot::new()
//!     .title("LowerRight")
//!     .legend_position(LegendPosition::LowerRight)
//!     .line(&x, &y_sin).label("sin(x)")
//!     .line(&x, &y_cos).label("cos(x)")
//!     .end_series();
//!
//! // Combine in 2x2 subplots
//! subplots(2, 2, 800, 600)?
//!     .suptitle("Legend Positions")
//!     .subplot_at(0, plot_ul)?
//!     .subplot_at(1, plot_ur)?
//!     .subplot_at(2, plot_ll)?
//!     .subplot_at(3, plot_lr)?
//!     .save("legend_positions.png")?;
//! # Ok::<(), Box<dyn std::error::Error>>(())
//! ```
//!
//! **Subplots**
//! ```rust,no_run
//! use ruviz::prelude::*;
//!
//! let x: Vec<f64> = (0..50).map(|i| i as f64 * 0.2).collect();
//!
//! let plot_line = Plot::new()
//!     .title("Line Plot")
//!     .line(&x, &x.iter().map(|&v| v.sin()).collect::<Vec<_>>())
//!     .end_series();
//!
//! let plot_scatter = Plot::new()
//!     .title("Scatter Plot")
//!     .scatter(&x, &x.iter().map(|&v| v.cos()).collect::<Vec<_>>())
//!     .end_series();
//!
//! let plot_bar = Plot::new()
//!     .title("Bar Chart")
//!     .bar(&["Q1", "Q2", "Q3", "Q4"], &[28.0, 45.0, 38.0, 52.0])
//!     .end_series();
//!
//! let plot_multi = Plot::new()
//!     .title("Comparison")
//!     .legend_position(LegendPosition::UpperRight)
//!     .line(&x, &x.iter().map(|&v| v.sin()).collect::<Vec<_>>()).label("sin")
//!     .line(&x, &x.iter().map(|&v| v.cos()).collect::<Vec<_>>()).label("cos")
//!     .end_series();
//!
//! subplots(2, 2, 800, 600)?
//!     .suptitle("Subplot Gallery")
//!     .subplot_at(0, plot_line)?
//!     .subplot_at(1, plot_scatter)?
//!     .subplot_at(2, plot_bar)?
//!     .subplot_at(3, plot_multi)?
//!     .save("subplots.png")?;
//! # Ok::<(), Box<dyn std::error::Error>>(())
//! ```
//!
//! </details>
//!
//! ### Internationalization
//!
//! | | | |
//! |:---:|:---:|:---:|
//! | <a href="https://raw.githubusercontent.com/Ameyanagi/ruviz/main/docs/assets/rustdoc/international_japanese.png"><img src="https://raw.githubusercontent.com/Ameyanagi/ruviz/main/docs/assets/rustdoc/international_japanese.png" width="250"></a> | <a href="https://raw.githubusercontent.com/Ameyanagi/ruviz/main/docs/assets/rustdoc/international_chinese.png"><img src="https://raw.githubusercontent.com/Ameyanagi/ruviz/main/docs/assets/rustdoc/international_chinese.png" width="250"></a> | <a href="https://raw.githubusercontent.com/Ameyanagi/ruviz/main/docs/assets/rustdoc/international_korean.png"><img src="https://raw.githubusercontent.com/Ameyanagi/ruviz/main/docs/assets/rustdoc/international_korean.png" width="250"></a> |
//! | 日本語 (Japanese) | 中文 (Chinese) | 한국어 (Korean) |
//! | <a href="https://raw.githubusercontent.com/Ameyanagi/ruviz/main/docs/assets/rustdoc/international_comparison.png"><img src="https://raw.githubusercontent.com/Ameyanagi/ruviz/main/docs/assets/rustdoc/international_comparison.png" width="350"></a> | | |
//! | Multi-language Comparison | | |
//!
//! <details>
//! <summary>Internationalization Code Examples</summary>
//!
//! **Japanese Labels**
//! ```rust,no_run
//! use ruviz::prelude::*;
//!
//! let x: Vec<f64> = (0..100).map(|i| i as f64 * 0.1).collect();
//! let y: Vec<f64> = x.iter().map(|&v| v.sin()).collect();
//!
//! Plot::new()
//!     .title("サイン波 (Sine Wave)")
//!     .xlabel("時間 (s)")
//!     .ylabel("振幅")
//!     .line(&x, &y)
//!     .label("sin(x)")
//!     .legend_best()
//!     .save("japanese_plot.png")?;
//! # Ok::<(), Box<dyn std::error::Error>>(())
//! ```
//!
//! **Chinese Labels**
//! ```rust,no_run
//! use ruviz::prelude::*;
//!
//! let categories = vec!["一月", "二月", "三月", "四月", "五月", "六月"];
//! let values = vec![28.0, 45.0, 38.0, 52.0, 47.0, 63.0];
//!
//! Plot::new()
//!     .title("月度销售数据")
//!     .xlabel("月份")
//!     .ylabel("销售额 (万元)")
//!     .bar(&categories, &values)
//!     .save("chinese_plot.png")?;
//! # Ok::<(), Box<dyn std::error::Error>>(())
//! ```
//!
//! </details>
//!
//! ### Animation
//!
//! Smooth animations with the `record!` macro (requires `animation` feature):
//!
//! | | | |
//! |:---:|:---:|:---:|
//! | <a href="https://raw.githubusercontent.com/Ameyanagi/ruviz/main/docs/assets/rustdoc/animation_sine_wave.gif"><img src="https://raw.githubusercontent.com/Ameyanagi/ruviz/main/docs/assets/rustdoc/animation_sine_wave.gif" width="250"></a> | <a href="https://raw.githubusercontent.com/Ameyanagi/ruviz/main/docs/assets/rustdoc/animation_bars.gif"><img src="https://raw.githubusercontent.com/Ameyanagi/ruviz/main/docs/assets/rustdoc/animation_bars.gif" width="250"></a> | <a href="https://raw.githubusercontent.com/Ameyanagi/ruviz/main/docs/assets/rustdoc/animation_spiral.gif"><img src="https://raw.githubusercontent.com/Ameyanagi/ruviz/main/docs/assets/rustdoc/animation_spiral.gif" width="250"></a> |
//! | Traveling Wave | Animated Bars | Spiral Growth |
//! | <a href="https://raw.githubusercontent.com/Ameyanagi/ruviz/main/docs/assets/rustdoc/animation_easing.gif"><img src="https://raw.githubusercontent.com/Ameyanagi/ruviz/main/docs/assets/rustdoc/animation_easing.gif" width="250"></a> | <a href="https://raw.githubusercontent.com/Ameyanagi/ruviz/main/docs/assets/rustdoc/animation_interference.gif"><img src="https://raw.githubusercontent.com/Ameyanagi/ruviz/main/docs/assets/rustdoc/animation_interference.gif" width="250"></a> | |
//! | Easing Functions | Wave Interference | |
//!
//! See [Animation Gallery](https://github.com/Ameyanagi/ruviz/blob/main/docs/gallery/animation/README.md) for more examples.
//!
//! ## Quick Start
//!
//! ```rust,no_run
//! use ruviz::prelude::*;
//!
//! let x = vec![0.0, 1.0, 2.0, 3.0, 4.0];
//! let y = vec![0.0, 1.0, 4.0, 9.0, 16.0];
//!
//! Plot::new()
//!     .line(&x, &y)
//!     .title("Quadratic Function")
//!     .xlabel("x")
//!     .ylabel("y = x^2")
//!     .save("plot.png")?;
//! # Ok::<(), Box<dyn std::error::Error>>(())
//! ```
//!
//! ### With Legend (matplotlib-style)
//!
//! ```rust,no_run
//! use ruviz::prelude::*;
//!
//! let x: Vec<f64> = (0..100).map(|i| i as f64 * 0.1).collect();
//! let sin_y: Vec<f64> = x.iter().map(|&v| v.sin()).collect();
//! let cos_y: Vec<f64> = x.iter().map(|&v| v.cos()).collect();
//!
//! Plot::new()
//!     .title("Trigonometric Functions")
//!     .line(&x, &sin_y).label("sin(x)")
//!     .line(&x, &cos_y).label("cos(x)")
//!     .end_series()     // Finish series chain
//!     .legend_best()    // Enable legend (like plt.legend())
//!     .save("trig.png")?;
//! # Ok::<(), Box<dyn std::error::Error>>(())
//! ```
//!
//! ### Figure Size and DPI
//!
//! ```rust,no_run
//! use ruviz::prelude::*;
//!
//! let x: Vec<f64> = (0..100).map(|i| i as f64 * 0.1).collect();
//! let y: Vec<f64> = x.iter().map(|&v| v.sin()).collect();
//!
//! Plot::new()
//!     .size(8.0, 6.0)  // 8×6 inches
//!     .dpi(300)        // 300 DPI = 2400×1800 pixels
//!     .line(&x, &y)
//!     .save("high_res.png")?;
//! # Ok::<(), Box<dyn std::error::Error>>(())
//! ```
//!
//! ### Named Colors
//!
//! ```rust,no_run
//! use ruviz::prelude::*;
//!
//! let x: Vec<f64> = (0..50).map(|i| i as f64 * 0.2).collect();
//! let y: Vec<f64> = x.iter().map(|&v| v.sin()).collect();
//!
//! // Use named colors (no unwrap needed!)
//! let color = Color::named("coral").unwrap_or(Color::RED);
//!
//! Plot::new()
//!     .line(&x, &y).color(color)
//!     .save("colored.png")?;
//! # Ok::<(), Box<dyn std::error::Error>>(())
//! ```

#[cfg(target_os = "freebsd")]
fn setup_freebsd_fontconfig() {
    use std::env;

    // Set FONTCONFIG_FILE if not already set
    if env::var("FONTCONFIG_FILE").is_err() {
        let fontconfig_path = "/usr/local/etc/fonts/fonts.conf";
        if std::path::Path::new(fontconfig_path).exists() {
            // SAFETY: This runs in a process constructor before worker threads start.
            // Setting process env vars at that point avoids concurrent env mutation.
            unsafe {
                env::set_var("FONTCONFIG_FILE", fontconfig_path);
            }
        }
    }
}

// Call it using ctor to run before any cosmic-text initialization
#[cfg(target_os = "freebsd")]
#[ctor::ctor]
fn init_freebsd_fonts() {
    setup_freebsd_fontconfig();
}

pub mod axes;
pub mod core;
pub mod data;
pub mod export;
pub mod layout;
pub mod plots;
pub mod render;
#[cfg(not(target_arch = "wasm32"))]
pub mod simple;
pub mod stats;
pub mod style;
pub mod text;

#[cfg(all(feature = "interactive", not(target_arch = "wasm32")))]
pub mod interactive;

#[cfg(all(feature = "animation", not(target_arch = "wasm32")))]
pub mod animation;

/// Convenience re-exports for common usage
pub mod prelude {
    pub use crate::axes::AxisScale;
    pub use crate::core::{
        Annotation, ArrowHead, ArrowStyle, BackendType, FillStyle, FramePacing, FrameStats,
        GridSpec, HatchPattern, HitResult, Image, ImageTarget, InsetAnchor, InsetLayout,
        InteractiveFrame, InteractivePlotSession, InteractiveViewportSnapshot, IntoPlot,
        LayerRenderState, Legend, LegendAnchor, LegendItem, LegendItemType, LegendPosition, Plot,
        PlotBuilder, PlotInput, PlotInputEvent, PlotSource, Position, PreparedPlot, QualityPolicy,
        ReactiveSubscription, ReactiveValue, RenderTargetKind, Result, SeriesStyle, ShapeStyle,
        SubplotFigure, SurfaceCapability, SurfaceTarget, TextAlign, TextStyle, TextVAlign,
        TickDirection, TickSides, ViewportPoint, ViewportRect, subplots, subplots_default,
    };
    pub use crate::data::{
        Data1D, DataShader, DataShaderCanvas, NullPolicy, NumericData1D, NumericData2D,
    };
    pub use crate::plots::{
        ContourConfig, HeatmapConfig, Interpolation, PieConfig, PlotArea, PlotCompute, PlotConfig,
        PlotData, PlotRender, PolarPlotConfig, RadarConfig, ViolinConfig,
    };
    pub use crate::render::{
        Color, ColorMap, FontConfig, FontFamily, FontStyle, FontWeight, LineStyle, MarkerStyle,
        Theme,
    };

    // Top-level convenience functions
    pub use crate::{bar, line, scatter};

    #[cfg(all(feature = "interactive", not(target_arch = "wasm32")))]
    pub use crate::interactive::{
        event::{InteractionEvent, Point2D, Rectangle, Vector2D},
        renderer::RealTimeRenderer,
        state::InteractionState,
        window::{
            InteractiveContextMenuActionContext, InteractiveContextMenuConfig,
            InteractiveContextMenuItem, InteractiveWindow, InteractiveWindowBuilder,
            show_interactive,
        },
    };

    #[cfg(all(feature = "animation", not(target_arch = "wasm32")))]
    #[allow(deprecated)]
    pub use crate::animation::{
        DurationExt, RecordConfig, Signal, Tick, easing, record_plot, record_simple, signal,
    };
}

// =============================================================================
// Top-Level Convenience Functions
// =============================================================================

use core::{Plot, PlotBuilder};
use data::NumericData1D;
use plots::{BarConfig, LineConfig, ScatterConfig};

/// Create a line plot with the given data.
///
/// This is a convenience function equivalent to `Plot::new().line(x, y)`.
///
/// # Arguments
///
/// * `x` - X-axis data (any type implementing `NumericData1D`)
/// * `y` - Y-axis data (any type implementing `NumericData1D`)
///
/// # Returns
///
/// A `PlotBuilder` that can be further configured.
///
/// # Example
///
/// ```rust,no_run
/// use ruviz::{line, prelude::*};
///
/// let x: Vec<f64> = (0..100).map(|i| i as f64 * 0.1).collect();
/// let y: Vec<f64> = x.iter().map(|&v| v.sin()).collect();
///
/// line(&x, &y)
///     .title("Sine Wave")
///     .xlabel("x")
///     .ylabel("sin(x)")
///     .save("sine.png")?;
/// # Ok::<(), Box<dyn std::error::Error>>(())
/// ```
pub fn line<X, Y>(x: &X, y: &Y) -> PlotBuilder<LineConfig>
where
    X: NumericData1D,
    Y: NumericData1D,
{
    Plot::new().line(x, y)
}

/// Create a scatter plot with the given data.
///
/// This is a convenience function equivalent to `Plot::new().scatter(x, y)`.
///
/// # Arguments
///
/// * `x` - X-axis data (any type implementing `NumericData1D`)
/// * `y` - Y-axis data (any type implementing `NumericData1D`)
///
/// # Returns
///
/// A `PlotBuilder` that can be further configured.
///
/// # Example
///
/// ```rust,no_run
/// use ruviz::{scatter, prelude::*};
///
/// let x = vec![1.0, 2.0, 3.0, 4.0, 5.0];
/// let y = vec![2.0, 4.0, 1.0, 5.0, 3.0];
///
/// scatter(&x, &y)
///     .title("Scatter Plot")
///     .marker(MarkerStyle::Circle)
///     .save("scatter.png")?;
/// # Ok::<(), Box<dyn std::error::Error>>(())
/// ```
pub fn scatter<X, Y>(x: &X, y: &Y) -> PlotBuilder<ScatterConfig>
where
    X: NumericData1D,
    Y: NumericData1D,
{
    Plot::new().scatter(x, y)
}

/// Create a bar plot with the given categories and values.
///
/// This is a convenience function equivalent to `Plot::new().bar(categories, values)`.
///
/// # Arguments
///
/// * `categories` - Category labels for the bars
/// * `values` - Values for each bar (any type implementing `NumericData1D`)
///
/// # Returns
///
/// A `PlotBuilder` that can be further configured.
///
/// # Example
///
/// ```rust,no_run
/// use ruviz::{bar, prelude::*};
///
/// let categories = vec!["A", "B", "C", "D"];
/// let values = vec![10.0, 25.0, 15.0, 30.0];
///
/// bar(&categories, &values)
///     .title("Bar Chart")
///     .ylabel("Count")
///     .save("bar.png")?;
/// # Ok::<(), Box<dyn std::error::Error>>(())
/// ```
pub fn bar<S, V>(categories: &[S], values: &V) -> PlotBuilder<BarConfig>
where
    S: ToString,
    V: NumericData1D,
{
    Plot::new().bar(categories, values)
}
