using System;

namespace Volpe.Cafe.DfsSrModels
{
    /// <summary>
    /// Represents the forecast fleet data for a single model year and for a specific fleet.
    /// </summary>
    [Serializable]
    public class ForecastFleetData
    {
        /// <summary>
        /// Gets or sets the sales volumes accumulated across all forecast vehicles within a specific fleet.
        /// </summary>
        public double Sales { get; set; }
        /// <summary>
        /// Gets or sets the share of a specific fleet with regard to the total light-duty fleet. This value is only
        /// applicable to the light-duty fleet (cars and trucks) and should be set to 1.0 for the HDPUV fleet.
        /// </summary>
        public double Share { get; set; }

        /// <summary>
        /// Gets or sets the average fuel economy rating of forecast vehicles for each fuel type.
        /// </summary>
        public FuelValue RatedFE { get; set; }
        /// <summary>
        /// Gets or sets the average on-road fuel economy rating of forecast vehicles for each fuel type.
        /// </summary>
        public FuelValue OnRoadFE { get; set; }
        /// <summary>
        /// Gets or sets the average fuel share of forecast vehicles for each fuel type.
        /// </summary>
        public FuelValue FuelShare { get; set; }

        /// <summary>Gets the combined fuel economy rating of forecast vehicles.</summary>
        public double AverageRatedFE => 1 / (this.FuelShare / this.RatedFE).Total;
        /// <summary>Gets the combined on-road fuel economy rating of forecast vehicles.</summary>
        public double AverageOnRoadFE => 1 / (this.FuelShare / this.OnRoadFE).Total;

        /// <summary>Gets or sets the average vehicle power rating of forecast vehicles.</summary>
        public double VehiclePower { get; set; }
        /// <summary>Gets or sets the average curb weight of forecast vehicles.</summary>
        public double CurbWeight { get; set; }

        /// <summary>Gets or sets the average regulatory costs of forecast vehicles.</summary>
        public double RegCost { get; set; }
        /// <summary>Gets or sets the average additional vehicle tax credits of forecast vehicles.</summary>
        public double TaxCredit { get; set; }
        /// <summary>Gets or sets the average additional battery tax credits of forecast vehicles.</summary>
        public double BatteryTaxCredit { get; set; }

        /// <summary>
        /// Combines the specified two forecast fleet data values, by sales-weighting items as necessary.
        /// </summary>
        internal static ForecastFleetData Combine(ForecastFleetData value1, ForecastFleetData value2)
        {
            FuelValue xSalesFS = value1.Sales * value1.FuelShare;
            FuelValue ySalesFS = value2.Sales * value2.FuelShare;
            FuelValue combinedSalesFS = xSalesFS + ySalesFS;
            double combinedSales = value1.Sales + value2.Sales;

            var combinedFleet = new ForecastFleetData {
                Sales = combinedSales,
                Share = value1.Share + value2.Share,

                RatedFE = AverageFE(value1.RatedFE, value2.RatedFE),
                OnRoadFE = AverageFE(value1.OnRoadFE, value2.OnRoadFE),
                FuelShare = combinedSalesFS / combinedSales,

                VehiclePower = AverageValue(value1.VehiclePower, value2.VehiclePower),
                CurbWeight = AverageValue(value1.CurbWeight, value2.CurbWeight),
                RegCost = AverageValue(value1.RegCost, value2.RegCost),
                TaxCredit = AverageValue(value1.TaxCredit, value2.TaxCredit),
                BatteryTaxCredit = AverageValue(value1.BatteryTaxCredit, value2.BatteryTaxCredit)
            };

            return combinedFleet;

            // local helper functions
            FuelValue AverageFE(FuelValue fe1, FuelValue fe2)
            {
                return FuelValue.SafeDivide(combinedSalesFS, FuelValue.SafeDivide(xSalesFS, fe1)
                                                           + FuelValue.SafeDivide(ySalesFS, fe2));
            }

            double AverageValue(double d1, double d2)
            {
                return (d1 * value1.Sales + d2 * value2.Sales) / combinedSales;
            }
        }

    }
}
