#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member

using System;
using System.Collections.Generic;
using Volpe.Cafe.Generic;
using Volpe.Cafe.ModelSettings;

namespace Volpe.Cafe.DfsSrModels.Aggregators
{
    /// <summary>
    /// Provides methods for aggregating forecast fleet data from individual forecast vehicles or from the historic
    /// fleet data based on vehicle classification.
    /// </summary>
    [Serializable]
    public sealed class ForecastFleetAggregatorVehClass : IForecastFleetAggregator
    {
        /// <summary>
        /// Initializes a new instances of the <see cref="ForecastFleetAggregatorVehClass"/> class, using the following
        /// modeling <paramref name="settings"/>.
        /// </summary>
        /// <param name="settings">The modeling settings used for analysis.</param>
        public ForecastFleetAggregatorVehClass(ModelingSettings settings)
        {
            this.Settings = settings;
            this.MinYear = this.Settings.RuntimeSettings.AnalysisStartYear;
        }

        public ModelingSettings Settings { get; }
        private int MinYear { get; }

        public ForecastFleet AggregateFleetData(Scenario scen, int year, IList<ForecastVehicle> forecastVehs)
        {
            ForecastFleet forecastFleet = (year < this.MinYear)
                ? this.AggregateHistoricFleetData(scen, year)
                : this.AggregateAnalysisFleetData(scen, year, forecastVehs);

            return forecastFleet;
        }

        public ForecastFleet AggregateAnalysisFleetData(Scenario scen, int year, IList<ForecastVehicle> forecastVehs)
        {
            var econValues = this.Settings.Parameters.EconomicValues;
            var forecastFleet = new VCValue<ForecastFleetData>(() => new ForecastFleetData());

            foreach (var veh in forecastVehs) {
                var vehData = veh.ForecastData[year];
                var fleetData = forecastFleet[DfsSrHelpers.GetBinningVehClass(vehData)];

                ForecastFleetAggregatorUtils.AggregateVehicleData(vehData, fleetData, scen, year, econValues);
            }

            ForecastFleetAggregatorUtils.FinalizeFleetData(
                forecastFleet.Ldv, forecastFleet.Ldt12a, forecastFleet.Ldt2b3);

            return ForecastFleet.FromVCValue(forecastFleet);
        }

        public ForecastFleet AggregateHistoricFleetData(Scenario scen, int year)
        {
            var historicFleetData = this.Settings.Parameters.HistoricFleetData;

            var carHfd = historicFleetData.GetHistoricFleetData(VehicleStyle.GenericCar, year);
            var vanSuvHfd = historicFleetData.GetHistoricFleetData(VehicleStyle.GenericVanSUV, year);
            var pickupHfd = historicFleetData.GetHistoricFleetData(VehicleStyle.GenericPickup, year);
            var hdpuvHfd = historicFleetData.GetHistoricFleetData(VehicleStyle.Generic2b3, year);

            // car and 2b3 fleets have direct mapping to their respective styles
            var carData = ForecastFleetAggregatorUtils.FromHistoricFleetData(carHfd);
            var hdpuvData = ForecastFleetAggregatorUtils.FromHistoricFleetData(hdpuvHfd);

            // truck fleet maps to combination of van/suv & pickup styles
            // hence, we need to combine the historic fleet data
            var vanSuvData = ForecastFleetAggregatorUtils.FromHistoricFleetData(vanSuvHfd);
            var pickupData = ForecastFleetAggregatorUtils.FromHistoricFleetData(pickupHfd);
            var truckData = ForecastFleetData.Combine(vanSuvData, pickupData);

            // finalize fleet shares for cars and trucks
            double totalLdSales = carData.Sales + truckData.Sales;
            carData.Share = carData.Sales / totalLdSales;
            truckData.Share = truckData.Sales / totalLdSales;

            return new ForecastFleet(carData, truckData, hdpuvData);
        }

    }
}
