using System;
using System.Collections.Generic;
using Winbooks.TORM.OM;
using Winbooks.TORM.OM.Accounting;
using Winbooks.TORM.DAL;
using Winbooks.TORM.DAL.Accounting;
using Winbooks.Apis.Services;
using Winbooks.Apis.Services.v2;
using Currency = Winbooks.TORM.OM.Currency;


namespace Winbooks.Apis.Demo
{
    public class PostBankCash
    {
        private static EntitiesServices _folder;

        public static string MainExecute(EntitiesServices folder)
        {
            Tools.LogFile = "c:\\temp\\PostBankCash.log";
            _folder = folder;
            return ExecutePostBankCash();
        }

        private static string ExecutePostBankCash()
        {
            string msg;

            Console.WriteLine("Posting Bank & Cash operation ...");
            GLTrans glTransInvoice = GetEntity.GetGLTrans(_folder, "VERKOPEN", 1); if (glTransInvoice == null) return "VERKOPEN 1 not found";

            decimal paidAmount = glTransInvoice.Amount;

            BookPeriod bookPeriod = GetEntity.GetBookPeriod(_folder, 2015, 3); if (bookPeriod == null) return "Book period 2015 3 not found";
            Journal journal = GetEntity.GetJournal(_folder, "KBC", bookPeriod); if (journal == null) return "Journal KBC not found";
            Currency currency = GetEntity.GetCurrency(_folder, "EUR"); if (currency == null) return "Currency EUR not found";
            GLAccount custAccount = GetEntity.GetGLAccount(_folder, "400000", bookPeriod); if (custAccount == null) return "GLAccount 400000 not found";
            GLAccount bankAccount = _folder.GetById<GLAccount>(journal.GLAccount_Id); if (bankAccount == null) return "GLAccount of KBC not found";


            // CREATE HEADER
            GLTransHeader header = new GLTransHeader();
            header.BookPeriod_Id = bookPeriod.Id;
            header.Journal_Id = journal.Id;
            header.DocNumber = GetNextDocNumber(journal.Id);
            header.BookDate = DateTime.Parse("2015-03-15T00:00:00");

            // CREATE TRANSACTION FOR CUSTOMER
            GLTrans glTransCustomer = CreateTransaction(header, bookPeriod, glTransInvoice.Customer, currency);
            glTransCustomer.GLAccount_Id = custAccount.Id;
            glTransCustomer.CentralAccountType_Id = custAccount.CentralAccountType_Id;
            glTransCustomer.Customer_Id = glTransInvoice.Customer.Id;
            glTransCustomer.Amount = -paidAmount;
            glTransCustomer.CurrencyAmount = -paidAmount;
            glTransCustomer.OldestMatchedDate = header.BookDate;
            glTransCustomer.LineOrder = 1000;
            glTransCustomer.CommentBooking = "Payment injected";
            header.GLTransactions.Add(glTransCustomer);

            // CREATE TRANSACTION FOR BANK
            GLTrans glTransBank = CreateTransaction(header, bookPeriod, null, currency);
            glTransBank.GLAccount_Id = bankAccount.Id;
            glTransBank.CentralAccountType_Id = bankAccount.CentralAccountType_Id;
            glTransBank.Amount = paidAmount;
            glTransBank.CurrencyAmount = paidAmount;
            glTransBank.OldestMatchedDate = header.BookDate;
            glTransBank.LineOrder = 1020;
            glTransBank.CommentBooking = "Contra payment injected";
            glTransCustomer.SubGLTransactions.Add(glTransBank);
            header.GLTransactions.Add(glTransBank);

            msg = "GLTransHeader + 2 level " + journal.Code + "  " + header.DocNumber.ToString() + " in " + bookPeriod.Name;
            Tools.Log("Creating " + msg, true);
            _folder.Insert<GLTransHeader>(header, 3);
            Tools.Log("Creating " + msg + " : OK");
            header = GetEntity.GetGLTransHeader(_folder, journal.Code, header.DocNumber);

            glTransCustomer = GetEntity.GetGLTrans(_folder, journal.Code, header.DocNumber, glTransCustomer.LineOrder.Value);
            glTransBank = GetEntity.GetGLTrans(_folder, journal.Code, header.DocNumber, glTransBank.LineOrder.Value);

            // MATCHING THE CUSTOMER TRANSACTION OF INVOICE AND BANK

            List<GLTrans> glTransList = new List<GLTrans>();
            glTransList.Add(glTransInvoice);
            glTransList.Add(glTransCustomer);
            Match(glTransList);

            // PUTING GLTransBank AS Sub transaction OF GLTransCustomer

            msg = "Putting bank contrapart as subtransaction of customer payment";
            Tools.Log(msg, true);
            glTransBank.Parent = glTransCustomer;
            _folder.UpdateById<GLTrans>(glTransBank, 1);
            Tools.Log(msg + " done");

            return "OK";
        }

        private static GLTrans CreateTransaction(GLTransHeader header, BookPeriod bookPeriod, Customer customer, Currency currency)
        {
            if (header == null) return null;

            GLTrans glTrans = new GLTrans();
            glTrans.GLTransHeader_Id = header.Id;
            glTrans.BookPeriod_Id = bookPeriod.Id;
            glTrans.Currency_Id = currency.Id;
            glTrans.CurrencyRate = 1;
            glTrans.ValueDate = header.BookDate;
            if (customer != null)
                glTrans.Customer_Id = customer.Id;
            glTrans.IsCoda = false;
            return glTrans;
        }

        private static long GetNextDocNumber(Guid journalId)
        {
            //GET LAST GLTRANSHEADER DOCUMENT NUMBER
            Tools.Log("Getting the last Document Number of journal", true);
            var lastHeaderCriteria = new GLTransHeaderDAO().CreateCriteria()
                .Add(Condition.Eq(GLTransHeader.Names.Journal_Id, journalId))
                .Order(GLTransHeader.Names.DocNumber, false)
                .SetFirstResult(0).SetMaxResults(1);

            GLTransHeader lastHeader = _folder.GetFilter<GLTransHeader>(lastHeaderCriteria);
            long documentNumber = 1;

            if (lastHeader != null)
            {
                Tools.Log("Getting the last Document Number (" + lastHeader.DocNumber + ") : OK");
                documentNumber = lastHeader.DocNumber + 1;
            }
            else
                Tools.Log("Folder has no document in the journal");
            return documentNumber;
        }

        private static void Match(List<GLTrans> glTransList)
        {
            // If the GLMatch does not exist, create it
            string code = "123457";
            GLMatch glMatch;

            glMatch = _folder.GetByCode<GLMatch>(code, true);
            if (glMatch == null)
            {
                glMatch = new GLMatch();
                glMatch.Code = code;
                _folder.Insert<GLMatch>(glMatch);
                glMatch = _folder.GetByCode<GLMatch>(code, true);
            }

            // Put the GLTrans in the GLMatch
            decimal total = 0;
            glMatch.GLTransactions = new List<GLTrans>();
            foreach (var glTrans in glTransList)
            {
                total += glTrans.Amount;
                glMatch.GLTransactions.Add(glTrans);
                glTrans.GLMatch = glMatch;
            }
            if (total == 0)
                glMatch.IsMatched = true;

            Tools.Log("Matching transactions", true);
            _folder.UpdateCollection<GLTrans>(glTransList, 3);
            Tools.Log("Matching transactions done");

            if (total == 0)
            {
                Tools.Log("Updating IsMatch = true", true);
                _folder.UpdateById<GLMatch>(glMatch, 1);
                Tools.Log("Updating IsMatch = true done");
            }
        }

    }
}
