por favor, analiza en profundidad toda la logica de creacion de la serie de estacionalidad porque no funciona correctamente.     public enum EnumSeasonalityModel
    {
        Additive,
        Multiplicative
    };

    public enum EnumSeasonalityCalculationMethod
    {
        Mean,
        Median
    };

    public interface ISeasonalityCalculator
    {
        SeasonalityResult CalculateSeasonality(IReadOnlyList<DateTime> dates, IReadOnlyList<double> prices);
        double[] GenerateSeasonalitySeries(IReadOnlyList<DateTime> dates);
    }

    public record SeasonalityResult(double[] SeasonalIndices);

    public record DataPoint(DateTime Date, double Price);

    public class AdvancedSeasonalityCalculator : ISeasonalityCalculator
    {
        private readonly EnumSeasonalityModel _model;
        private readonly ISeasonalityMethodStrategy _calculationMethod;
        private readonly IDataFiller _dataFiller;
        private readonly int _lookbackYears;
        private Dictionary<int, double[]> _seasonalIndicesByYear;

        public AdvancedSeasonalityCalculator(
            EnumSeasonalityModel model,
            ISeasonalityMethodStrategy calculationMethod,
            IDataFiller dataFiller,
            int lookbackYears)
        {
            _model = model;
            _calculationMethod = calculationMethod ?? throw new ArgumentNullException(nameof(calculationMethod));
            _dataFiller = dataFiller ?? throw new ArgumentNullException(nameof(dataFiller));
            _lookbackYears = lookbackYears;

            // Precalcular índices estacionales por año utilizando el lookback especificado
            _seasonalIndicesByYear = new Dictionary<int, double[]>();
        }

        public SeasonalityResult CalculateSeasonality(IReadOnlyList<DateTime> dates, IReadOnlyList<double> prices)
        {
            ValidateInput(dates, prices);

            var sortedData = CreateSortedData(dates, prices);
            var dataByYear = GroupDataByYear(sortedData);

            ValidateYearlyData(dataByYear);

            var (historicalData, _) = SplitData(dataByYear);
            _seasonalIndicesByYear = PrecalculateSeasonalIndicesByYear(historicalData);

            return new SeasonalityResult(_seasonalIndicesByYear.SelectMany(kv => kv.Value).ToArray());
        }

        private Dictionary<int, double[]> PrecalculateSeasonalIndicesByYear(List<DataPoint> historicalData)
        {
            var seasonalIndicesByYear = new Dictionary<int, double[]>();

            foreach (var yearGroup in historicalData.GroupBy(dp => dp.Date.Year))
            {
                int currentYear = yearGroup.Key;
                List<DataPoint> lookbackData;

                // Si lookbackYears es 0, usamos todos los datos previos al año actual
                if (_lookbackYears == 0)
                {
                    lookbackData = historicalData.Where(dp => dp.Date.Year < currentYear).ToList();
                }
                else
                {
                    // Si no, usamos la cantidad especificada de años previos
                    lookbackData = FilterHistoricalData(historicalData, currentYear - _lookbackYears, currentYear - 1);
                }

                // En caso de no tener datos suficientes, saltamos o usamos valores predeterminados
                if (lookbackData.Count == 0)
                {
                    seasonalIndicesByYear[currentYear] = DefaultSeasonalIndices();
                }
                else
                {
                    seasonalIndicesByYear[currentYear] = CalculateSeasonalIndicesForYear(lookbackData);
                }
            }

            return seasonalIndicesByYear;
        }

        private List<DataPoint> FilterHistoricalData(List<DataPoint> data, int startYear, int endYear)
        {
            return data.Where(dp => dp.Date.Year >= startYear && dp.Date.Year <= endYear).ToList();
        }

        private double[] CalculateSeasonalIndicesForYear(List<DataPoint> lookbackData)
        {
            var filledData = _dataFiller.FillMissingDays(lookbackData);
            var dayOfYearGroups = GroupByDayOfYear(filledData);
            return CalculateIndicesForEachDay(dayOfYearGroups);
        }

        public double[] GenerateSeasonalitySeries(IReadOnlyList<DateTime> dates)
        {
            if (dates == null)
                throw new ArgumentNullException(nameof(dates));

            return dates.Select(date =>
            {
                int currentYear = date.Year;
                int dayOfYear = AdjustDayForLeapYear(date);

                // Definir el rango de años para el lookback: si lookback es 0, usar todos los años previos disponibles.
                var yearsToConsider = _lookbackYears == 0
                    ? _seasonalIndicesByYear.Keys.Where(y => y < currentYear).ToList()
                    : _seasonalIndicesByYear.Keys.Where(y => y < currentYear && y >= currentYear - _lookbackYears).ToList();

                // Si no hay años disponibles, devuelve el valor por defecto
                if (!yearsToConsider.Any())
                    return DefaultSeasonalValue();

                // Recolectar los valores de los índices estacionales del mismo día en años anteriores
                var seasonalValues = yearsToConsider
                    .Where(year => _seasonalIndicesByYear[year].Length > dayOfYear)
                    .Select(year => _seasonalIndicesByYear[year][dayOfYear])
                    .Where(value => value > 0) // Filtrar valores válidos (omitimos 0s o faltantes)
                    .ToList();

                // Si no hay valores estacionales válidos para este día, devolver valor por defecto
                if (!seasonalValues.Any())
                    return DefaultSeasonalValue();

                // Calcular el promedio de los valores estacionales de los años previos
                return seasonalValues.Average();
            }).ToArray();
        }

        private double DefaultSeasonalValue()
        {
            return _model == EnumSeasonalityModel.Multiplicative ? 1.0 : 0.0;
        }


        private void ValidateInput(IReadOnlyList<DateTime> dates, IReadOnlyList<double> prices)
        {
            if (dates == null) throw new ArgumentNullException(nameof(dates));
            if (prices == null) throw new ArgumentNullException(nameof(prices));
            if (dates.Count != prices.Count) throw new ArgumentException("Lists must have same length");
            if (dates.Count < 365 * 2) throw new ArgumentException("Insufficient data points");
        }

        private List<DataPoint> CreateSortedData(IReadOnlyList<DateTime> dates, IReadOnlyList<double> prices)
        {
            return dates.Zip(prices, (date, price) => new DataPoint(date, price))
                       .OrderBy(dp => dp.Date)
                       .ToList();
        }

        private IReadOnlyList<IGrouping<int, DataPoint>> GroupDataByYear(List<DataPoint> sortedData)
        {
            return sortedData.GroupBy(dp => dp.Date.Year)
                            .OrderBy(g => g.Key)
                            .ToList();
        }

        private void ValidateYearlyData(IReadOnlyList<IGrouping<int, DataPoint>> dataByYear)
        {
            if (dataByYear.Count < 2)
                throw new ArgumentException("At least two full years of data required");
        }

        private (List<DataPoint> historical, List<DataPoint> analyzed) SplitData(
                IReadOnlyList<IGrouping<int, DataPoint>> dataByYear)
        {
            var historical = dataByYear.Take(dataByYear.Count - 1)
                                     .SelectMany(g => g)
                                     .ToList();
            var analyzed = dataByYear.Last()
                                    .ToList();
            return (historical, analyzed);
        }

        private Dictionary<int, List<double>> GroupByDayOfYear(List<DataPoint> data)
        {
            var groups = new Dictionary<int, List<double>>();

            foreach (var point in data)
            {
                int day = point.Date.DayOfYear;
                if (DateTime.IsLeapYear(point.Date.Year) && day == 60)
                    continue;

                if (!groups.ContainsKey(day))
                    groups[day] = new List<double>();

                groups[day].Add(point.Price);
            }

            return groups;
        }

        private double[] CalculateIndicesForEachDay(Dictionary<int, List<double>> dayGroups)
        {
            int maxDay = dayGroups.Keys.Max();
            var indices = new double[maxDay + 1];

            for (int day = 1; day <= maxDay; day++)
            {
                indices[day] = dayGroups.TryGetValue(day, out var values) && values.Count > 0
                    ? _calculationMethod.Calculate(values)
                    : InterpolateIndex(day, indices);
            }

            return NormalizeIndices(indices);
        }

        private double[] NormalizeIndices(double[] indices)
        {
            if (_model != EnumSeasonalityModel.Multiplicative)
                return indices;

            double average = indices.Where(x => x > 0).Average();
            return indices.Select(x => x > 0 ? x / average : x).ToArray();
        }

        private double InterpolateIndex(int day, double[] indices)
        {
            var (prevDay, nextDay) = FindNearestValidDays(day, indices);

            return CalculateInterpolatedValue(prevDay, nextDay, indices);
        }

        private (int prev, int next) FindNearestValidDays(int day, double[] indices)
        {
            int prevDay = day - 1;
            int nextDay = day + 1;

            while (prevDay >= 1 && indices[prevDay] == 0) prevDay--;
            while (nextDay < indices.Length && indices[nextDay] == 0) nextDay++;

            return (prevDay, nextDay);
        }

        private double CalculateInterpolatedValue(int prevDay, int nextDay, double[] indices)
        {
            if (prevDay >= 1 && nextDay < indices.Length)
                return (indices[prevDay] + indices[nextDay]) / 2.0;

            if (prevDay >= 1)
                return indices[prevDay];

            if (nextDay < indices.Length)
                return indices[nextDay];

            return _model == EnumSeasonalityModel.Multiplicative ? 1.0 : 0.0;
        }

        private int AdjustDayForLeapYear(DateTime date)
        {
            int day = date.DayOfYear;
            return DateTime.IsLeapYear(date.Year) && day == 60 ? 59 : day;
        }

        private double[] DefaultSeasonalIndices()
        {
            return Enumerable.Repeat(_model == EnumSeasonalityModel.Multiplicative ? 1.0 : 0.0, 366).ToArray();
        }
    }

    // Interfaces y clases de apoyo
    public interface ISeasonalityMethodStrategy
    {
        double Calculate(IEnumerable<double> values);
    }

    public class MeanStrategy : ISeasonalityMethodStrategy
    {
        public double Calculate(IEnumerable<double> values)
            => values.Average();
    }

    public class MedianStrategy : ISeasonalityMethodStrategy
    {
        public double Calculate(IEnumerable<double> values)
        {
            var sortedValues = values.OrderBy(x => x).ToList();
            int mid = sortedValues.Count / 2;
            return sortedValues.Count % 2 == 0
                ? (sortedValues[mid - 1] + sortedValues[mid]) / 2
                : sortedValues[mid];
        }
    }

    public interface IDataFiller
    {
        List<DataPoint> FillMissingDays(List<DataPoint> data);
    };

    public class LinearDataFiller : IDataFiller
    {
        public List<DataPoint> FillMissingDays(List<DataPoint> data)
        {
            if (!data.Any()) return new List<DataPoint>();

            var filledData = new List<DataPoint>();
            var firstDate = data.Min(d => d.Date);
            var lastDate = data.Max(d => d.Date);
            var currentDate = firstDate;
            var dataDict = data.ToDictionary(d => d.Date, d => d.Price);

            while (currentDate <= lastDate)
            {
                if (dataDict.TryGetValue(currentDate, out var price))
                {
                    filledData.Add(new DataPoint(currentDate, price));
                }
                else
                {
                    double interpolatedPrice = InterpolatePrice(currentDate, dataDict);
                    filledData.Add(new DataPoint(currentDate, interpolatedPrice));
                }

                currentDate = currentDate.AddDays(1);
            }

            return filledData;
        }

        private double InterpolatePrice(DateTime date, Dictionary<DateTime, double> dataDict)
        {
            var prevDate = date.AddDays(-1);
            var nextDate = date.AddDays(1);

            while (!dataDict.ContainsKey(prevDate) && prevDate >= dataDict.Keys.Min()) prevDate = prevDate.AddDays(-1);
            while (!dataDict.ContainsKey(nextDate) && nextDate <= dataDict.Keys.Max()) nextDate = nextDate.AddDays(1);

            if (dataDict.ContainsKey(prevDate) && dataDict.ContainsKey(nextDate))
                return (dataDict[prevDate] + dataDict[nextDate]) / 2.0;

            return dataDict.ContainsKey(prevDate) ? dataDict[prevDate] : dataDict[nextDate];
        }
    }
    // Factory para crear la calculadora
    public class SeasonalityCalculatorFactory
    {
        public static ISeasonalityCalculator Create(EnumSeasonalityModel model, EnumSeasonalityCalculationMethod method)
        {
            ISeasonalityMethodStrategy strategy = method switch
            {
                EnumSeasonalityCalculationMethod.Mean => new MeanStrategy(),
                EnumSeasonalityCalculationMethod.Median => new MedianStrategy(),
                _ => throw new ArgumentException("Invalid calculation method")
            };

            return new AdvancedSeasonalityCalculator(model, strategy, new LinearDataFiller(), 10);
        }
    };