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

/// Top holding in an ETF.
pub const Holding = struct {
    symbol: ?[]const u8 = null,
    name: []const u8,
    weight: f64,
};

/// Sector allocation in an ETF.
pub const SectorWeight = struct {
    name: []const u8,
    weight: f64,
};

/// ETF profile and metadata.
pub const EtfProfile = struct {
    symbol: []const u8,
    name: ?[]const u8 = null,
    asset_class: ?[]const u8 = null,
    /// Expense ratio as a decimal (e.g., 0.0003 for 0.03%)
    expense_ratio: ?f64 = null,
    /// Net assets in USD
    net_assets: ?f64 = null,
    /// Morningstar-style category (e.g., "Large Blend")
    category: ?[]const u8 = null,
    /// Investment focus description
    description: ?[]const u8 = null,
    /// Top holdings
    holdings: ?[]const Holding = null,
    /// Number of total holdings in the fund
    total_holdings: ?u32 = null,
    /// Sector allocations
    sectors: ?[]const SectorWeight = null,
    /// Dividend yield as decimal (e.g., 0.0111 for 1.11%)
    dividend_yield: ?f64 = null,
    /// Portfolio turnover as decimal
    portfolio_turnover: ?f64 = null,
    /// Fund inception date
    inception_date: ?Date = null,
    /// Whether the fund is leveraged
    leveraged: bool = false,

    /// Returns true if the profile contains meaningful ETF data.
    /// Non-ETF symbols return empty profiles from Alpha Vantage.
    pub fn isEtf(self: EtfProfile) bool {
        return self.expense_ratio != null or
            self.net_assets != null or
            self.holdings != null or
            self.sectors != null or
            self.total_holdings != null;
    }

    /// Free any owned fields on this profile.
    ///
    /// Matches the inline cleanup previously inlined in
    /// `src/commands/etf.zig`. Only `holdings` and `sectors` are
    /// freed here — the top-level optional strings (`name`,
    /// `asset_class`, `category`, `description`) are borrowed from
    /// the cache store's shared buffer in the provider-fetched path
    /// and don't need freeing. If that changes (e.g., a provider
    /// starts allocating each field separately), extend this
    /// function accordingly.
    pub fn deinit(self: EtfProfile, allocator: std.mem.Allocator) void {
        if (self.holdings) |h| {
            for (h) |holding| {
                if (holding.symbol) |s| allocator.free(s);
                allocator.free(holding.name);
            }
            allocator.free(h);
        }
        if (self.sectors) |s| {
            for (s) |sec| allocator.free(sec.name);
            allocator.free(s);
        }
    }
};

const std = @import("std");

test "isEtf" {
    // Empty profile -> not an ETF
    const empty = EtfProfile{ .symbol = "AAPL" };
    try std.testing.expect(!empty.isEtf());
    // Has expense_ratio -> is ETF
    const with_er = EtfProfile{ .symbol = "VTI", .expense_ratio = 0.0003 };
    try std.testing.expect(with_er.isEtf());
    // Has net_assets -> is ETF
    const with_na = EtfProfile{ .symbol = "SPY", .net_assets = 500_000_000_000 };
    try std.testing.expect(with_na.isEtf());
    // Has total_holdings -> is ETF
    const with_th = EtfProfile{ .symbol = "QQQ", .total_holdings = 100 };
    try std.testing.expect(with_th.isEtf());
}
