#nullable enable
using System.ComponentModel.DataAnnotations;
using Exilion.TradingAtomics;
using Managing.Domain.Bots;
using Managing.Domain.Candles;
using Managing.Domain.Indicators;
using Managing.Domain.Trades;
using Managing.Domain.Users;

namespace Managing.Domain.Backtests;

public class Backtest
{
    public Backtest(
        TradingBotConfig config,
        Dictionary<Guid, Position> positions,
        Dictionary<string, LightSignal> signals,
        HashSet<Candle> candles = null)
    {
        Config = config;
        Positions = positions;
        Signals = signals;
        Candles = candles != null ? candles : new HashSet<Candle>();
        WalletBalances = new List<KeyValuePair<DateTime, decimal>>();

        // Initialize start and end dates if candles are provided
        if (candles != null && candles.Count > 0)
        {
            StartDate = candles.Min(c => c.Date);
            EndDate = candles.Max(c => c.Date);
        }
        else
        {
            StartDate = DateTime.UtcNow.AddDays(-30);
            EndDate = DateTime.UtcNow;
        }
    }

    [Required] public string Id { get; set; }
    [Required] public decimal FinalPnl { get; set; }
    [Required] public int WinRate { get; set; }
    [Required] public decimal GrowthPercentage { get; set; }
    [Required] public decimal HodlPercentage { get; set; }
    [Required] public TradingBotConfig Config { get; }
    [Required] public Dictionary<Guid, Position> Positions { get; }
    [Required] public Dictionary<string, LightSignal> Signals { get; }
    [Required] public HashSet<Candle> Candles { get; set; }
    [Required] public DateTime StartDate { get; set; }
    [Required] public DateTime EndDate { get; set; }
    [Required] public PerformanceMetrics Statistics { get; set; }
    [Required] public decimal Fees { get; set; }
    [Required] public List<KeyValuePair<DateTime, decimal>> WalletBalances { get; set; }
    [Required] public User User { get; set; }
    [Required] public double Score { get; set; }
    public string RequestId { get; set; }
    public object? Metadata { get; set; }
    public string ScoreMessage { get; set; } = string.Empty;

    /// <summary>
    /// Creates a new TradingBotConfig based on this backtest's configuration for starting a live bot.
    /// This method ensures all properties are properly copied, including nullable values.
    /// </summary>
    /// <param name="accountName">The account name to use for the new bot (can override backtest account)</param>
    /// <param name="botName">The name for the new bot</param>
    /// <param name="initialTradingBalance">The initial trading balance for the new bot</param>
    /// <param name="moneyManagement">Optional money management override (uses backtest's if not provided)</param>
    /// <returns>A new TradingBotConfig ready for bot creation</returns>
    public TradingBotConfig CreateLiveBotConfig(
        string accountName,
        string botName,
        decimal initialTradingBalance,
        LightMoneyManagement moneyManagement = null)
    {
        return new TradingBotConfig
        {
            AccountName = accountName,
            MoneyManagement = moneyManagement ?? Config.MoneyManagement,
            Ticker = Config.Ticker,
            ScenarioName = Config.ScenarioName,
            Timeframe = Config.Timeframe,
            IsForWatchingOnly = false, // Always start as active bot
            BotTradingBalance = initialTradingBalance,
            IsForBacktest = false, // Always false for live bots
            CooldownPeriod = Config.CooldownPeriod,
            MaxLossStreak = Config.MaxLossStreak,
            MaxPositionTimeHours = Config.MaxPositionTimeHours, // Properly copy nullable value
            FlipOnlyWhenInProfit = Config.FlipOnlyWhenInProfit,
            FlipPosition = Config.FlipPosition,
            Name = botName
        };
    }

    /// <summary>
    /// Creates a copy of the backtest's configuration for a new backtest.
    /// Useful for running similar backtests with modified parameters.
    /// </summary>
    /// <param name="startDate">Start date for the new backtest</param>
    /// <param name="endDate">End date for the new backtest</param>
    /// <param name="balance">Initial balance for the new backtest</param>
    /// <param name="moneyManagement">Optional money management override</param>
    /// <returns>A new TradingBotConfig for backtesting</returns>
    public TradingBotConfig CreateBacktestConfig(
        DateTime startDate,
        DateTime endDate,
        decimal balance,
        LightMoneyManagement moneyManagement = null)
    {
        return new TradingBotConfig
        {
            AccountName = Config.AccountName,
            MoneyManagement = moneyManagement ?? Config.MoneyManagement,
            Ticker = Config.Ticker,
            ScenarioName = Config.ScenarioName,
            Timeframe = Config.Timeframe,
            IsForWatchingOnly = Config.IsForWatchingOnly,
            BotTradingBalance = balance,
            IsForBacktest = true,
            CooldownPeriod = Config.CooldownPeriod,
            MaxLossStreak = Config.MaxLossStreak,
            MaxPositionTimeHours = Config.MaxPositionTimeHours,
            FlipOnlyWhenInProfit = Config.FlipOnlyWhenInProfit,
            FlipPosition = Config.FlipPosition,
            Name = Config.Name
        };
    }

    public string GetStringReport()
    {
        var timeBasedInfo = Config.MaxPositionTimeHours.HasValue
            ? $" | MaxTime: {Config.MaxPositionTimeHours}h"
            : " | MaxTime: Disabled";

        var flipInfo = Config.FlipPosition
            ? $" | Flip: {(Config.FlipOnlyWhenInProfit ? "Profit-Only" : "Always")}"
            : "";

        return
            $"{Config.Ticker} | {Config.Timeframe} | Positions: {Positions.Count} | Winrate: {WinRate}% | " +
            $"Pnl: {FinalPnl:#.##}$ | %Pnl: {GrowthPercentage:#.##}% | %Hodl: {HodlPercentage:#.##}%" +
            $" | Cooldown: {Config.CooldownPeriod} | MaxLoss: {Config.MaxLossStreak}" +
            timeBasedInfo + flipInfo;
    }
}