using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Winbooks.Apis.Services;
using Winbooks.Apis.Services.v2;
using Winbooks.TORM.OM;
using Winbooks.TORM.OM.Accounting;

namespace Winbooks.Apis.Linker
{
    /// <summary>
    /// This class allows to post Sales/Credit notes
    /// </summary>
    public class MiscOpLinker : CommonLinker
    {

        public MiscOpLinker(EntitiesServices folder, Settings settings, Cache cache)
            : base(folder, settings, cache)
        { }

        /// <summary>
        /// Post the invoice in the accounting
        /// Throw an error (System.ArgumentException) if something is wrong
        /// </summary>
        /// <param name="invoiceHeader"></param>
        /// <param name="bookPeriod"></param>
        /// <returns>The Id of the transaction header</returns>
        public Guid PostMiscOp(MiscOpHeader miscOpHeader, BookPeriod bookPeriod)
        {
            if (_settings == null || string.IsNullOrEmpty(_settings.FolderCurrency))
                throw new ArgumentException("Settings was not initialized");
            CheckParameters(miscOpHeader, bookPeriod);
            GLTransHeader header = CreateGLTransHeader(miscOpHeader, bookPeriod);
            return header.Id;
        }

        private void CheckParameters(MiscOpHeader miscOpHeader, BookPeriod bookPeriod)
        {
            if (miscOpHeader == null)
                throw new System.ArgumentException("Cannot PostInvoice with miscOpHeader == null");
            if (bookPeriod == null)
                throw new System.ArgumentException("Cannot PostInvoice with miscOpHeader == null");

            if (miscOpHeader.DocNumber <= 0)
                throw new System.ArgumentException("DocNumber must be defined");

            if (string.IsNullOrEmpty(miscOpHeader.JournalCode))
                throw new ArgumentException("The Journal is not defined");
            if (miscOpHeader.Journal.Type != JournalType.MiscellaneousOperation)
                throw new System.ArgumentException(string.Format("The journal {0} is not a miscellaneous operation journal", miscOpHeader.Journal.Code));
            if (bookPeriod.IsMiscellaneousOperationClosed)
                throw new System.ArgumentException(string.Format("Journal {0}: the period {1} is closed for miscellaneous operations", miscOpHeader.Journal.Code, bookPeriod.Name));
        }

        private void ComputeTotals(MiscOpHeader miscOpHeader)
        {
            if (miscOpHeader.details == null)
                throw new ArgumentException("MiscOpHeader.Details is null");

            decimal total = 0;
            foreach (MiscOpDetail miscOpDetail in miscOpHeader.details)
            {
                if (string.IsNullOrEmpty(miscOpDetail.Sign) || (!miscOpDetail.Sign.Equals("D") && !miscOpDetail.Sign.Equals("C")))
                    throw new ArgumentException("The Sign must be \"D\" or \"C\"");
                if (miscOpDetail.Currency == null)
                    throw new ArgumentException("The MiscOpDetail.CurrencyCode must be defined");

                short dec = miscOpDetail.Currency.NumberOfDecimals == null ? (short)2 : (short)miscOpDetail.Currency.NumberOfDecimals;
                total += CheckRounded(miscOpDetail.Sign.Equals("D") ? miscOpDetail.Amount : -miscOpDetail.Amount, _settings.NumberOfDecimals);
            }
            if (total != 0)
                throw new ArgumentException("The total in the folder currency is not 0");
        }

        private GLTransHeader CreateGLTransHeader(MiscOpHeader miscOpHeader, BookPeriod bookPeriod)
        {
            int lineOrder = 1000;

            // CREATE HEADER
            GLTransHeader header = new GLTransHeader();
            header.BookPeriod_Id = bookPeriod.Id;
            header.Journal_Id = miscOpHeader.Journal.Id;
            header.DocNumber = miscOpHeader.DocNumber;
            header.BookDate = miscOpHeader.BookDate;

            foreach (MiscOpDetail miscOpDetail in miscOpHeader.details)
            {
                GLTrans glTran = new GLTrans()
                {
                    BookPeriod_Id = bookPeriod.Id,
                    CommentBooking = miscOpDetail.Comment,
                    Currency = miscOpDetail.Currency,
                    CurrencyRate = miscOpDetail.CurrencyRate,
                    LineOrder = lineOrder,
                    ValueDate = miscOpDetail.ValueDate,
                    Amount = miscOpDetail.Sign.Equals("D") ? miscOpDetail.Amount : -miscOpDetail.Amount,
                    CurrencyAmount = miscOpDetail.Sign.Equals("D") ? miscOpDetail.CurrencyAmount : -miscOpDetail.CurrencyAmount
                };
                lineOrder += 1000;
                if (miscOpDetail.GLAccount != null)
                {
                    glTran.GLAccount_Id = miscOpDetail.GLAccount.Id;
                    glTran.CentralAccountType_Id = miscOpDetail.GLAccount.CentralAccountType_Id;
                }
                else if (miscOpDetail.Customer != null)
                {
                    glTran.GLAccount_Id = GetCentralGLAccountCustomer(miscOpDetail.Customer);
                    glTran.CentralAccountType_Id = _defaultCentralAccountCustomer.CentralAccountType_Id;
                    glTran.Customer_Id = miscOpDetail.Customer.Id;
                }
                else if (miscOpDetail.Supplier != null)
                {
                    glTran.GLAccount_Id = GetCentralGLAccountCustomer(miscOpDetail.Customer);
                    glTran.CentralAccountType_Id = _defaultCentralAccountCustomer.CentralAccountType_Id;
                    glTran.Customer_Id = miscOpDetail.Customer.Id;
                }
                header.GLTransactions.Add(glTran);
            }

            GLTransHeader glTransHeaderBack = _folder.Insert(header, 2);
            return glTransHeaderBack;
        }
    }
}
