using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Serialization;
using CareFusion.Mosaic.Interfaces.Converters;
using CareFusion.Mosaic.Interfaces.Messages;
using CareFusion.Mosaic.Interfaces.Messages.Input;
using CareFusion.Mosaic.Interfaces.Types.Packs;
using CareFusion.Mosaic.Interfaces.Types.Stock;
using Rowa.Mosaic.Shared.Converters;

namespace CareFusion.Mosaic.Converters.Wwks2.Messages.Input
{
    /// <summary>
    /// Class which represents the WWKS 2.0 InputRequest message envelope.
    /// </summary>
    [XmlType(TypeName = "WWKS")]
    public class InputRequestEnvelope : EnvelopeBase, IMessageConversion
    {
        [XmlElement]
        public InputRequest InputRequest { get; set; }

        /// <summary>
        /// Translates this object instance into a Mosaic message.
        /// </summary>
        /// <param name="converterStream">The converter stream instance which request the message conversion.</param>
        /// <returns>
        /// The Mosaic message representation of this object.
        /// </returns>
        public MosaicMessage ToMosaicMessage(IConverterStream converterStream)
        {
            return this.InputRequest.ToMosaicMessage(converterStream);
        }
    }

    /// <summary>
    /// Class which represents the WWKS 2.0 InputRequest message.
    /// <see cref="https://portalrowa.carefusion.com/Unternehmen/Entwicklung/TechCom/Writing/P-010-044-B-I-388-DEU.docx" />
    /// </summary>
    public class InputRequest : MessageBase, IInputRequest
    {
        #region IInputRequest Specific Properties

        /// <inheritdoc/>
        [XmlAttribute]
        public bool IsNewDelivery { get; set; }

        /// <inheritdoc/>
        [XmlAttribute]
        public bool SetPickingIndicator { get; set; }

        /// <inheritdoc/>
        [XmlElement]
        public InputRequestArticle Article { get; set; }

        [XmlElement]
        public InputComponent InputComponent { get; set; }

        #endregion

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="InputRequest"/> class.
        /// </summary>
        public InputRequest()
        {
            this.Article = new InputRequestArticle();
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="InputRequest"/> class.
        /// </summary>
        /// <param name="message">The message to use for initialization.</param>
        public InputRequest(MosaicMessage message)
        {
            if (message == null)
            {
                return;
            }

            var stockInputRequest = (StockInputRequest)message;

            this.Id = stockInputRequest.ID;
            this.Source = stockInputRequest.Source;
            this.Destination = stockInputRequest.Destination;
            this.IsNewDelivery = stockInputRequest.IsDeliveryInput;
            this.SetPickingIndicator = stockInputRequest.SetPickingIndicator;
            this.InputComponent = new InputComponent
            {
                Name = stockInputRequest.ComponentName,
                Id = stockInputRequest.ComponentId
            };

            if (stockInputRequest.Packs?.FirstOrDefault() == null)
            {
                this.Article = new InputRequestArticle();

                return;
            }

            var inputRequestPacks = new List<InputRequestPack>();

            for (int i = 0; i < stockInputRequest.Packs.Count; ++i)
            {
                inputRequestPacks.Add(new InputRequestPack
                {
                    Index = (uint)i,
                    ScanCode = TextConverter.EscapeInvalidXmlChars(stockInputRequest.Packs[i].ScanCode),
                    BatchNumber = TextConverter.EscapeInvalidXmlChars(stockInputRequest.Packs[i].BatchNumber),
                    SerialNumber = TextConverter.EscapeInvalidXmlChars(stockInputRequest.Packs[i].SerialNumber),
                    ExternalId = TextConverter.EscapeInvalidXmlChars(stockInputRequest.Packs[i].ExternalID),
                    DeliveryNumber = stockInputRequest.IsDeliveryInput ? TextConverter.EscapeInvalidXmlChars(stockInputRequest.Packs[i].DeliveryNumber) : null,
                    ExpiryDate = TypeConverter.ConvertDateNull(stockInputRequest.Packs[i].ExpiryDate),
                    ExpiryDateSource = stockInputRequest.Packs[i].ExpiryDateSource.ToString() ?? ExpiryDateSource.Unknown.ToString(),
                    SubItemQuantity = (uint)stockInputRequest.Packs[i].SubItemQuantity,
                    StockLocationId = TextConverter.EscapeInvalidXmlChars(stockInputRequest.Packs[i].StockLocationID),
                    MachineLocation = TextConverter.EscapeInvalidXmlChars(stockInputRequest.Packs[i].MachineLocation),
                    GUID = Guid.Parse(TextConverter.EscapeInvalidXmlChars(stockInputRequest.Packs[i].Guid.ToString()))
                });
            }

            this.Article = new InputRequestArticle
            {
                Id = inputRequestPacks.FirstOrDefault()?.ScanCode,
                Packs = inputRequestPacks
            };
        }

        #endregion

        #region IMessageConversion Specific properties

        /// <inheritdoc/>
        public MosaicMessage ToMosaicMessage(IConverterStream converterStream)
        {
            if (converterStream == null)
            {
                return default;
            }

            var stockInputRequest = new StockInputRequest(converterStream)
            {
                ID = this.Id,
                Source = this.Source,
                Destination = this.Destination,
                IsDeliveryInput = this.IsNewDelivery,
                SetPickingIndicator = this.SetPickingIndicator
            };

            if (this.Article.Packs?.FirstOrDefault() == null)
            {
                return stockInputRequest;
            }

            foreach (var pack in this.Article.Packs)
            {
                stockInputRequest.Packs.Add(new RobotPack
                { 
                    ScanCode = TextConverter.UnescapeInvalidXmlChars(pack.ScanCode),
                    BatchNumber = TextConverter.UnescapeInvalidXmlChars(pack.BatchNumber),
                    ExternalID = TextConverter.UnescapeInvalidXmlChars(pack.ExternalId),
                    DeliveryNumber = TextConverter.UnescapeInvalidXmlChars(pack.DeliveryNumber),
                    ExpiryDate = TypeConverter.ConvertDate(pack.ExpiryDate),
                    ExpiryDateSource = TypeConverter.ConvertEnum<ExpiryDateSource>(pack.ExpiryDateSource, ExpiryDateSource.Unknown),
                    SubItemQuantity = (int)pack.SubItemQuantity,
                    StockLocationID = string.IsNullOrEmpty(pack.StockLocationId) ? string.Empty : TextConverter.UnescapeInvalidXmlChars(pack.StockLocationId),
                    MachineLocation = string.IsNullOrEmpty(pack.MachineLocation) ? string.Empty : TextConverter.UnescapeInvalidXmlChars(pack.MachineLocation),
                    Guid = pack.GUID
                });
            }

            return stockInputRequest;
        }

        #endregion
    }
}
