const Date = @import("../Date.zig");

/// A single OHLCV bar, normalized from any provider.
pub const Candle = struct {
    date: Date,
    open: f64,
    high: f64,
    low: f64,
    close: f64,
    /// Close price adjusted for splits and dividends (for total return calculations).
    /// If the provider does not supply this, it equals `close`.
    adj_close: f64,
    volume: u64,

    /// Close value to use when rendering charts. Returns `adj_close`
    /// if it is non-zero, otherwise falls back to raw `close`.
    ///
    /// Why: charts should render split-adjusted prices so the line
    /// doesn't show artificial cliffs at split dates (e.g. SOXX
    /// 3-for-1 on 2024-03-07, NVDA 10-for-1 on 2024-06-10). Some
    /// older cached candles or providers that don't populate
    /// `adj_close` leave it at 0; in that case the raw close is
    /// the best we can do.
    pub fn chartClose(self: Candle) f64 {
        return if (self.adj_close != 0) self.adj_close else self.close;
    }
};

test "chartClose prefers adj_close when populated" {
    const std = @import("std");
    const c = Candle{
        .date = Date.fromYmd(2024, 3, 7),
        .open = 700.0,
        .high = 700.0,
        .low = 230.0,
        .close = 237.75, // raw post-split
        .adj_close = 234.0, // split-adjusted
        .volume = 0,
    };
    try std.testing.expectEqual(@as(f64, 234.0), c.chartClose());
}

test "chartClose falls back to close when adj_close is zero" {
    const std = @import("std");
    const c = Candle{
        .date = Date.fromYmd(2024, 1, 1),
        .open = 100.0,
        .high = 100.0,
        .low = 100.0,
        .close = 100.0,
        .adj_close = 0,
        .volume = 0,
    };
    try std.testing.expectEqual(@as(f64, 100.0), c.chartClose());
}

test "chartClose synthetic split has continuous chart values" {
    const std = @import("std");
    // Pre-split: close=300, adj_close=100 (after a 3:1 split)
    // Post-split: close=100, adj_close=100
    // Chart should see [100, 100] not [300, 100].
    const pre = Candle{
        .date = Date.fromYmd(2024, 3, 6),
        .open = 300,
        .high = 300,
        .low = 300,
        .close = 300,
        .adj_close = 100,
        .volume = 0,
    };
    const post = Candle{
        .date = Date.fromYmd(2024, 3, 7),
        .open = 100,
        .high = 100,
        .low = 100,
        .close = 100,
        .adj_close = 100,
        .volume = 0,
    };
    try std.testing.expectEqual(pre.chartClose(), post.chartClose());
}
