#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.Initializers;
using Volpe.Cafe.MarketData.Design;
using Volpe.Cafe.Utils;

namespace Volpe.Cafe.MarketData.BaselineInfo
{
    /// <summary>
    /// Provides a description of baseline engineering characteristics for a manufacturer.
    /// </summary>
    /// <seealso cref="IManufacturer"/>
    [Serializable]
    public sealed class BaselineManufacturer : IManufacturerInfo
    {
        #region <<< Nested Types >>>

        /// <summary>
        /// Represents an object that stores manufacturer's willingness to pay fines for each regulatory class and
        /// model year.
        /// <br/>
        /// This object supports and operates on all regulatory classes as defined by <see cref="RegClasses.AltList"/>.
        /// The <see cref="PreferFinesValue"/> is a read-only object, the contents of which cannot be modified once
        /// created.
        /// </summary>
        [Serializable]
        public sealed class PreferFinesValue
        {
            /// <summary>
            /// Initializes a new instance of the <see cref="PreferFinesValue"/> class, based on the specified range
            /// of years and object of values.
            /// </summary>
            public PreferFinesValue(int minYear, int maxYear, RCValue<bool[]> values)
            {
                this.Values = new RCValue<AnnualValue<bool>>();
                for (int i = 0; i < values.Items.Length; i++) {
                    this.Values.Items[i] = new AnnualValue<bool>(
                        minYear, maxYear, values.Items[i].CloneArray(), outOfBoundsMode: 1);
                }
            }

            /// <summary>
            /// Gets the manufacturer's willingness to pay fines based on the given <see cref="RegulatoryClass"/> and
            /// model year.
            /// </summary>
            public bool this[RegulatoryClass regClass, int year] => this.Values[regClass][year];

            private RCValue<AnnualValue<bool>> Values { get; }
        }

        /// <summary>
        /// Represents an object that stores payback periods for each vehicle style category.
        /// <br/>
        /// This object supports and operates on all vehicle styles or categories as defined by
        /// <see cref="VehicleStyles.AltList"/>. The <see cref="PaybackPeriodValue"/> is a read-only object, the
        /// contents of which cannot be modified once created.
        /// </summary>
        [Serializable]
        public sealed class PaybackPeriodValue
        {
            /// <summary>
            /// Initializes a new instance of the <see cref="PaybackPeriodValue"/> class, based on the specified object
            /// of values.
            /// </summary>
            public PaybackPeriodValue(VSValue<double> values)
            {
                this.Values = values.Clone();
            }

            /// <summary>
            /// Gets the payback period based on the given <see cref="VehicleStyle"/>.
            /// </summary>
            public double this[VehicleStyle vehStyle] => this.Values[vehStyle];

            private VSValue<double> Values { get; }

            /// <summary>
            /// Defines an explicit conversion of a <see cref="PaybackPeriodValue"/> to an <see cref="VSValue{T}"/>
            /// equivalent.
            /// </summary>
            public static explicit operator VSValue<double>(PaybackPeriodValue value)
            {
                return value.Values.Clone();
            }
        }

        /// <summary>
        /// Represents an object that stores EPA multiplier modes for each regulatory class, with the domestic and
        /// imported cars combined into a single passenger car regulatory class.
        /// <br/>
        /// This object supports and operates on all regulatory classes as defined by <see cref="RegClasses.AltList"/>.
        /// The <see cref="EPAMultiplierModeValue"/> is a read-only object, the contents of which cannot be modified
        /// once created.
        /// </summary>
        [Serializable]
        public sealed class EPAMultiplierModeValue
        {
            /// <summary>
            /// Initializes a new instance of the <see cref="EPAMultiplierModeValue"/> class, based on the specified
            /// object of values.
            /// </summary>
            public EPAMultiplierModeValue(RCAltValue<int> values)
            {
                this.Values = values.Clone();
            }

            /// <summary>
            /// Gets the EPA multiplier mode based on the given <see cref="RegulatoryClass"/>.
            /// </summary>
            public int this[RegulatoryClass regClass] => this.Values[regClass];

            private RCAltValue<int> Values { get; }

            /// <summary>
            /// Defines an explicit conversion of a <see cref="EPAMultiplierModeValue"/> to an
            /// <see cref="RCAltValue{T}"/> equivalent.
            /// </summary>
            public static explicit operator RCAltValue<int>(EPAMultiplierModeValue value)
            {
                return value.Values.Clone();
            }
        }

        #endregion

        #region <<< Constructors >>>

        /// <summary>
        /// Initializes a new instance of the <see cref="BaselineManufacturer"/> class.
        /// </summary>
        public BaselineManufacturer(Dictionary<string, object> values)
        {
            DataObjectInitializer.SetPropertyValues(this, values);

            // proper name is not defined in input or values dictionary
            this.ProperName = StringHelper.GetTitleCase(this.Name, 4);
        }

        #endregion

        #region <<< Properties >>>

        public int Code { get; private set; }
        public string Name { get; private set; }
        public string ProperName { get; } // auto-computed in ctor

        /// <summary>
        /// Gets whether the manufacturer prefers to pay CAFE civil penalties, instead of applying ineffective
        /// technology, for specific regulatory classes and model years.
        /// </summary>
        public PreferFinesValue PreferFines { get; private set; }

        /// <summary>
        /// Gets the manufacturer specific payback period, indicating the number of years required for an initial
        /// investment to be repaid in the form of future benefits or cost savings.
        /// </summary>
        public PaybackPeriodValue PaybackPeriod { get; private set; }

        /// <summary>
        /// Gets the percentage of manufacturer's total light duty fleet assumed to be sold in California and S177
        /// states during each model year.
        /// </summary>
        public IAnnualValue<double> ZevSalesShare { get; private set; }
        /// <summary>
        /// Gets the percentage of manufacturer's light duty fleet's ZEV credits assumed to be generated in California
        /// and S177 states.
        /// </summary>
        public double ZevCreditShare { get; private set; }
        /// <summary>
        /// Gets whether the PHEV cap (as defined in the parameters inputs) should be ignored when computing the amount
        /// of ZEV credits a manufacturer may generate from PHEVs for complying with the California and S177 states ZEV
        /// requirement. This setting is only applicable to the light duty fleet up to and including MY-2025.
        /// </summary>
        public bool IgnoreZevPhevCap { get; private set; }

        /// <summary>
        /// Gets the percentage of manufacturer's total HDPUV fleet assumed to be sold in California and S177 states.
        /// </summary>
        public double ZevSalesShareHDPUV { get; private set; }
        /// <summary>
        /// Gets the percentage of manufacturer's HDPUV fleet's ZEV credits assumed to be generated in California and
        /// S177 states.
        /// </summary>
        public double ZevCreditShareHDPUV { get; private set; }

        /// <summary>
        /// Gets whether the manufacturer is subject to the CARB agreement.
        /// </summary>
        public bool CARBAgreement { get; private set; }

        /// <summary>
        /// Gets the applicability of EPA production multipliers (defined in the compliance scenario) for computing a
        /// manufacturer's CO-2 standard, rating, and credits earned, when evaluating compliance with EPA's CO-2
        /// program.
        /// </summary>
        public EPAMultiplierModeValue EPAMultiplierMode { get; private set; }

        #endregion

        #region <<< Methods >>>

        /// <summary>
        /// Returns the string representation of this <see cref="BaselineManufacturer"/> instance.
        /// </summary>
        /// <returns>The string representation of the <see cref="BaselineManufacturer"/> instance.</returns>
        public override string ToString()
        {
            return this.ProperName;
        }

        /// <summary>
        /// Gets the percentage of manufacturer's fleet, of the specified regulatory class and model year, assumed to
        /// be sold in California and S177 states.
        /// </summary>
        public double GetZevSalesShare(RegulatoryClass regClass, int year)
        {
            return regClass.IsHDPUV() ? this.ZevSalesShareHDPUV : this.ZevSalesShare[year];
        }

        /// <summary>
        /// Gets the percentage of manufacturer's ZEV credits, for the fleet of the specified regulatory class, assumed
        /// to be generated in California and S177 states.
        /// </summary>
        public double GetZevCreditShare(RegulatoryClass regClass)
        {
            return regClass.IsHDPUV() ? this.ZevCreditShareHDPUV : this.ZevCreditShare;
        }

        #endregion
    }
}
