using System;
using System.Collections.Generic;

namespace Toolbox.Docking.Api.Objects.Metabolism
{
    /// <summary>
    /// Class representing a Toolbox metaboliser result.
    /// </summary>
    [Serializable]
    public sealed class MetabolResult
    {
        private readonly IReadOnlyList<string> _products;
        private readonly IReadOnlyList<float?> _productsQuantities;
        
        /// <summary>
        /// Metabolism result may be qualified by a remark.
        /// </summary>
        public readonly string Remark;
        /// <summary>
        /// If the metabolizer calculates quantities here is where the leftover parent quantity is recorded.
        /// </summary>
        /// <remarks>Quantities are recorded in <b>mol/mol parent</b>, in this case from 0 to 1.</remarks>
        public readonly float? ParentQuantity;

        /// <summary>
        /// Returns the resulting list of metabolism products.
        /// </summary>
        public IReadOnlyList<string> Products => _products != null ? _products : NoProducts;

        /// <summary>
        /// If the metabolizer calculates quantities this returns the product quantities.
        /// </summary>
        /// <remarks>Quantities are recorded in <b>mol/mol parent</b></remarks>
        public IReadOnlyList<float?> ProductsQuantities => _productsQuantities != null ? _productsQuantities : NoProductsQ;


        private static readonly IReadOnlyList<string> NoProducts = new List<string>();
        private static readonly IReadOnlyList<float?> NoProductsQ = new List<float?>();

        /// <summary>
        /// Constructor for creating a metabolism result that denotes a failed metabolisation.
        /// </summary>
        /// <param name="problem">Information on the metabolizer failure.</param>
        public MetabolResult(string problem)
        {
            _products = NoProducts;
            _productsQuantities = NoProductsQ;
            Remark = problem ?? string.Empty;
        }

        /// <summary>
        /// Constructor for a MetaboResult object.
        /// </summary>
        /// <param name="parentQuantity">Leftover parent quantity.</param>
        /// <param name="products">Metabolism products.</param>
        /// <param name="productsQuantities">Products list.</param>
        /// <remarks>Quantities are recorded in <b>mol/mol parent</b></remarks>
        public MetabolResult(float? parentQuantity, IEnumerable<string> products,
            IEnumerable<float?> productsQuantities)
        {
            Remark = string.Empty;
            ParentQuantity = parentQuantity;

            if (products != null)
            {
                _products = new List<string>(products);
                if (productsQuantities == null)
                    throw new ArgumentException("Metabolism products but not quantites!");
            }
            else _products = null;

            if (productsQuantities != null)
            {
                _productsQuantities = new List<float?>(productsQuantities);
                if (products == null)
                    throw new ArgumentException("Metabolism quantites but not products!");
                if (Products.Count != ProductsQuantities.Count)
                    throw new ArgumentException("Metabolism products and quantites count not match!");
            }
            else _productsQuantities = null;
        }
    }
}