using System.ComponentModel.DataAnnotations;
using Managing.Domain.Users;
using static Managing.Common.Enums;

namespace Managing.Domain.Backtests;

/// <summary>
/// Domain model for genetic algorithm optimization requests
/// </summary>
public class GeneticRequest
{
    public GeneticRequest()
    {
        RequestId = Guid.NewGuid().ToString();
        CreatedAt = DateTime.UtcNow;
        Status = GeneticRequestStatus.Pending;
        Results = new List<Backtest>();
    }

    /// <summary>
    /// Constructor that allows setting a specific ID
    /// </summary>
    /// <param name="requestId">The specific ID to use</param>
    public GeneticRequest(string requestId)
    {
        RequestId = requestId;
        CreatedAt = DateTime.UtcNow;
        Status = GeneticRequestStatus.Pending;
        Results = new List<Backtest>();
    }

    /// <summary>
    /// Unique identifier for the genetic request
    /// </summary>
    [Required]
    public string RequestId { get; set; }

    /// <summary>
    /// The user who created this request
    /// </summary>
    [Required]
    public User User { get; set; }

    /// <summary>
    /// When the request was created
    /// </summary>
    [Required]
    public DateTime CreatedAt { get; set; }

    /// <summary>
    /// When the request was completed (if completed)
    /// </summary>
    public DateTime? CompletedAt { get; set; }

    /// <summary>
    /// Current status of the genetic request
    /// </summary>
    [Required]
    public GeneticRequestStatus Status { get; set; }

    /// <summary>
    /// The ticker to optimize for
    /// </summary>
    [Required]
    public Ticker Ticker { get; set; }

    /// <summary>
    /// The timeframe to use for optimization
    /// </summary>
    [Required]
    public Timeframe Timeframe { get; set; }

    /// <summary>
    /// The start date for the backtest period
    /// </summary>
    [Required]
    public DateTime StartDate { get; set; }

    /// <summary>
    /// The end date for the backtest period
    /// </summary>
    [Required]
    public DateTime EndDate { get; set; }

    /// <summary>
    /// The starting balance for the backtest
    /// </summary>
    [Required]
    public decimal Balance { get; set; }

    /// <summary>
    /// The population size for the genetic algorithm
    /// </summary>
    [Required]
    public int PopulationSize { get; set; }

    /// <summary>
    /// The number of generations to evolve
    /// </summary>
    [Required]
    public int Generations { get; set; }

    /// <summary>
    /// The mutation rate (0.0 - 1.0)
    /// </summary>
    [Required]
    public double MutationRate { get; set; }

    /// <summary>
    /// The selection method to use
    /// </summary>
    [Required]
    public GeneticSelectionMethod SelectionMethod { get; set; } = GeneticSelectionMethod.Tournament;

    /// <summary>
    /// The crossover method to use
    /// </summary>
    [Required]
    public GeneticCrossoverMethod CrossoverMethod { get; set; } = GeneticCrossoverMethod.Uniform;

    /// <summary>
    /// The mutation method to use
    /// </summary>
    [Required]
    public GeneticMutationMethod MutationMethod { get; set; } = GeneticMutationMethod.Uniform;

    /// <summary>
    /// The percentage of elite individuals to preserve (1-50)
    /// </summary>
    [Required]
    public int ElitismPercentage { get; set; } = 15;

    /// <summary>
    /// The maximum take profit percentage
    /// </summary>
    [Required]
    public double MaxTakeProfit { get; set; } = 4.0;

    /// <summary>
    /// The list of eligible indicators to include in optimization
    /// </summary>
    [Required]
    public List<IndicatorType> EligibleIndicators { get; set; } = new();

    /// <summary>
    /// The results of the genetic algorithm optimization
    /// </summary>
    public List<Backtest> Results { get; set; } = new();

    /// <summary>
    /// The best fitness score achieved
    /// </summary>
    public double? BestFitness { get; set; }

    /// <summary>
    /// The best individual found
    /// </summary>
    public string? BestIndividual { get; set; }

    /// <summary>
    /// Error message if the request failed
    /// </summary>
    public string? ErrorMessage { get; set; }

    /// <summary>
    /// Progress information (JSON serialized)
    /// </summary>
    public string? ProgressInfo { get; set; }

    /// <summary>
    /// The best chromosome found so far (JSON serialized)
    /// </summary>
    public string? BestChromosome { get; set; }

    /// <summary>
    /// Current generation number when the algorithm was stopped
    /// </summary>
    public int CurrentGeneration { get; set; }

    /// <summary>
    /// The best fitness score achieved so far
    /// </summary>
    public double? BestFitnessSoFar { get; set; }
}

/// <summary>
/// Status of a genetic request
/// </summary>
public enum GeneticRequestStatus
{
    /// <summary>
    /// Request is pending execution
    /// </summary>
    Pending,

    /// <summary>
    /// Request is currently being processed
    /// </summary>
    Running,

    /// <summary>
    /// Request completed successfully
    /// </summary>
    Completed,

    /// <summary>
    /// Request failed with an error
    /// </summary>
    Failed,

    /// <summary>
    /// Request was cancelled
    /// </summary>
    Cancelled
}