using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Linq;
using System.Windows.Forms;
using MercatorApi;
using MercatorUi;
using MercatorUi.Engine.Gescom;
using MercatorExtensions;
using MercatorDatabase;
using MercatorUi.ICustomizers;

// <CompileWithRoslyn />

namespace Billing
{
    public class Customizer :
        IBillingEngineCreated,
        IBillingEngineClosed
    {
        public void BillingEngineCreated(BillingEngine billingEngine)
        {
            billingEngine.AfterInsertItem += BillingEngine_AfterInsertItem;
            billingEngine.BeforeDeleteLine += BillingEngine_BeforeDeleteLine;
            billingEngine.AfterDeleteLine += BillingEngine_AfterDeleteLine;
            billingEngine.GettingBareme += BillingEngine_GettingBareme;
            billingEngine.BeforeBeforePaymentOrSave += BillingEngine_BeforeBeforePaymentOrSave;
        }

        public void BillingEngineClosed(BillingEngine billingEngine)
        {
            billingEngine.AfterInsertItem -= BillingEngine_AfterInsertItem;
            billingEngine.BeforeDeleteLine -= BillingEngine_BeforeDeleteLine;
            billingEngine.AfterDeleteLine -= BillingEngine_AfterDeleteLine;
            billingEngine.GettingBareme -= BillingEngine_GettingBareme;
            billingEngine.BeforeBeforePaymentOrSave -= BillingEngine_BeforeBeforePaymentOrSave;
        }

        private void BillingEngine_AfterInsertItem(object sender, BillingEngine.AfterInsertItemEventArgs e)
        {
            BillingEngine billingEngine = (BillingEngine) sender;
            if (billingEngine.LignesVRecords.Where(l => l.ID_ART_GR == e.LignesVRecord.ID_ARTICLE).Any())
                billingEngine.ChangeAllPrices($"ID_ART_GR='{e.LignesVRecord.ID_ARTICLE}'");
        }

        private void BillingEngine_BeforeDeleteLine(object sender, BillingEngine.AfterDeleteLineEventArgs e)
        {
            BillingEngine billingEngine = (BillingEngine) sender;
            if (!string.IsNullOrWhiteSpace(e.LignesVRecord.ID_ART_GR))
            {
                var ligneASupprimer = billingEngine.LignesVRecords.Where(l => (billingEngine.LignesVRecords.Any(l2 => l.DL_ID_GRATUIT == l2.DL_ID)));

                if (ligneASupprimer?.Any() ?? false)
                {
                    foreach (var ligne in ligneASupprimer.ToList())
                    {
                        billingEngine.LignesVRecords.Where(l2 => l2.DL_ID == ligne.DL_ID_PARENT).ToList().ForEach(l => l.Q += ligne.Q);
                        billingEngine.LignesVRecords.Remove(ligne);
                    }
                }
            }
        }
        private void BillingEngine_AfterDeleteLine(object sender, BillingEngine.AfterDeleteLineEventArgs e)
        {
            BillingEngine billingEngine = (BillingEngine) sender;
            billingEngine.ChangeAllPrices();
        }
        private void BillingEngine_GettingBareme(object sender, BillingEngine.GettingBaremeEventArgs e)
        {
            BillingEngine billingEngine = (BillingEngine) sender;
            double totQ = billingEngine.LignesVRecords.Where(l => l.ID_ARTICLE == e.LigneVRecord.ID_ARTICLE).Sum(l => l.Q);
            double totQRayon = billingEngine.LignesVRecords.Where(l => !string.IsNullOrWhiteSpace(l.ID_ARTICLE) && billingEngine.StockRecords[l.ID_ARTICLE].S_ID_RAYON == billingEngine.StockRecords[e.LigneVRecord.ID_ARTICLE].S_ID_RAYON).Sum(l => l.Q);
            double totQFamille = billingEngine.LignesVRecords.Where(l => !string.IsNullOrWhiteSpace(l.ID_ARTICLE) && billingEngine.StockRecords[l.ID_ARTICLE].S_ID_FAMIL == billingEngine.StockRecords[e.LigneVRecord.ID_ARTICLE].S_ID_FAMIL).Sum(l => l.Q);
            double totQSsFam = billingEngine.LignesVRecords.Where(l => !string.IsNullOrWhiteSpace(l.ID_ARTICLE) && billingEngine.StockRecords[l.ID_ARTICLE].S_ID_SSFAM == billingEngine.StockRecords[e.LigneVRecord.ID_ARTICLE].S_ID_SSFAM).Sum(l => l.Q);
            double totQCat1 = billingEngine.LignesVRecords.Where(l => !string.IsNullOrWhiteSpace(l.ID_ARTICLE) && billingEngine.StockRecords[l.ID_ARTICLE].S_CAT1 == billingEngine.StockRecords[e.LigneVRecord.ID_ARTICLE].S_CAT1).Sum(l => l.Q);
            double totQCat2 = billingEngine.LignesVRecords.Where(l => !string.IsNullOrWhiteSpace(l.ID_ARTICLE) && billingEngine.StockRecords[l.ID_ARTICLE].S_CAT2 == billingEngine.StockRecords[e.LigneVRecord.ID_ARTICLE].S_CAT2).Sum(l => l.Q);
            double totQCat3 = billingEngine.LignesVRecords.Where(l => !string.IsNullOrWhiteSpace(l.ID_ARTICLE) && billingEngine.StockRecords[l.ID_ARTICLE].S_CAT3 == billingEngine.StockRecords[e.LigneVRecord.ID_ARTICLE].S_CAT3).Sum(l => l.Q);
            double totQOther = billingEngine.LignesVRecords.Where(l => !string.IsNullOrEmpty(l.ID_ARTICLE)).Sum(l => l.Q);

            if ((totQ.CompareTo(e.Qart, Globals.N_DEC_Q) != 0) || (totQRayon.CompareTo(e.Qrayon, Globals.N_DEC_Q) != 0) || (totQFamille.CompareTo(e.Qfamille, Globals.N_DEC_Q) != 0) || (totQSsFam.CompareTo(e.Qssfam, Globals.N_DEC_Q) != 0) || (totQCat1.CompareTo(e.Qcat1, Globals.N_DEC_Q) != 0)
                || (totQCat2.CompareTo(e.Qcat2, Globals.N_DEC_Q) != 0) || (totQCat3.CompareTo(e.Qcat3, Globals.N_DEC_Q) != 0) || (totQOther.CompareTo(e.Qother, Globals.N_DEC_Q) != 0))
            {
                e.Qart = totQ;
                e.Qcat1 = totQCat1;
                e.Qcat2 = totQCat2;
                e.Qcat3 = totQCat3;
                e.Qrayon = totQRayon;
                e.Qfamille = totQFamille;
                e.Qssfam = totQSsFam;
                e.Qother = totQOther;
            }

            BillingEngine.BeforeQYGratuitEventHandler beforeQYGratuitEventHandler = null;
            beforeQYGratuitEventHandler = (s, e2) =>
                {
                billingEngine.BeforeQYGratuit -= beforeQYGratuitEventHandler;
                if ((e.DataRowLignes == e2.DataRowLignes) && (!string.IsNullOrWhiteSpace(e2.LignesVRecord.ID_ART_GR) || ((e2.DataRowBaremes != null) && !string.IsNullOrWhiteSpace(e2.DataRowBaremes["ID_ART_GR"].ToString()))))
                {
                    var ligneASupprimer = billingEngine.LignesVRecords.Where(l => (billingEngine.LignesVRecords.Any(l2 => l.DL_ID_GRATUIT == l2.DL_ID && l2.ID_ART_GR == (string.IsNullOrWhiteSpace(e2.LignesVRecord.ID_ART_GR) ? e2.DataRowBaremes["ID_ART_GR"].ToString() : e2.LignesVRecord.ID_ART_GR))) && billingEngine.LignesVRecords.Any(l2 => (l2.DL_ID == l.DL_ID_PARENT)));

                    if (ligneASupprimer?.Any() ?? false)
                    {
                        foreach (var ligne in ligneASupprimer.ToList())
                        {
                            billingEngine.LignesVRecords.Where(l2 => l2.DL_ID == ligne.DL_ID_PARENT).ToList().ForEach(l => l.Q += ligne.Q);
                            billingEngine.LignesVRecords.Remove(ligne);
                        }
                    }
                }
                
                if ((e2.DataRowBaremes != null) && (!string.IsNullOrWhiteSpace(e2.DataRowBaremes["ID_ART_GR"].ToString())))
                {
                    e2.Cancel = true;
                    var lignesArticleGratuit = billingEngine.LignesVRecords.Where(l => l.ID_ARTICLE == e2.DataRowBaremes["ID_ART_GR"].ToString() && string.IsNullOrWhiteSpace(l.DL_ID_GRATUIT) && (l.Q.CompareTo(0, Globals.N_DEC_Q) > 0));
                    IEnumerable<LIGNES_V> lignesParent = null;
                    if (!string.IsNullOrWhiteSpace(e2.DataRowBaremes["ar_ref"].ToString()))
                    {
                        lignesParent = billingEngine.LignesVRecords.Where(l => (l.ID_ARTICLE == e.LigneVRecord.ID_ARTICLE));
                    }
                    else if (!string.IsNullOrWhiteSpace(e2.DataRowBaremes["id_fam"].ToString()))
                    {
                        MercatorDatabase.STOCK stockRecord = (e2.StockRecord ?? billingEngine.StockRecords[e2.LignesVRecord.ID_ARTICLE]);
                        switch (e2.DataRowBaremes["tag"].ToString())
                        {
                            case "4":
                            case "12":
                            case "20":
                                lignesParent = billingEngine.LignesVRecords.Where(l => !string.IsNullOrWhiteSpace(l.ID_ARTICLE) && billingEngine.StockRecords[l.ID_ARTICLE].S_ID_RAYON == stockRecord.S_ID_RAYON);
                                break;
                            case "3":
                            case "11":
                            case "19":
                                lignesParent = billingEngine.LignesVRecords.Where(l => !string.IsNullOrWhiteSpace(l.ID_ARTICLE) && billingEngine.StockRecords[l.ID_ARTICLE].S_ID_FAMIL == stockRecord.S_ID_FAMIL);
                                break;
                            case "2":
                            case "10":
                            case "18":
                                lignesParent = billingEngine.LignesVRecords.Where(l => !string.IsNullOrWhiteSpace(l.ID_ARTICLE) && billingEngine.StockRecords[l.ID_ARTICLE].S_ID_SSFAM == stockRecord.S_ID_SSFAM);
                                break;
                            case "5":
                            case "13":
                            case "21":
                                lignesParent = billingEngine.LignesVRecords.Where(l => !string.IsNullOrWhiteSpace(l.ID_ARTICLE) && billingEngine.StockRecords[l.ID_ARTICLE].S_CAT1 == stockRecord.S_CAT1);
                                break;
                            case "6":
                            case "14":
                            case "22":
                                lignesParent = billingEngine.LignesVRecords.Where(l => !string.IsNullOrWhiteSpace(l.ID_ARTICLE) && billingEngine.StockRecords[l.ID_ARTICLE].S_CAT2 == stockRecord.S_CAT2);
                                break;
                            case "7":
                            case "15":
                            case "23":
                                lignesParent = billingEngine.LignesVRecords.Where(l => !string.IsNullOrWhiteSpace(l.ID_ARTICLE) && billingEngine.StockRecords[l.ID_ARTICLE].S_CAT3 == stockRecord.S_CAT3);
                                break;
                        }
                    }
                    else
                    {
                        lignesParent = billingEngine.LignesVRecords.Where(l => !string.IsNullOrWhiteSpace(l.ID_ARTICLE));
                    }
                    double totQForGratuit = lignesParent.Sum(l => l.Q);
                    double nbGratis = Math.Truncate(totQForGratuit / (Convert.ToDouble(e2.DataRowBaremes["q_fact"]))) * Convert.ToDouble(e2.DataRowBaremes["q_gratuit"]);
                    lignesParent.ToList().ForEach(l => l.ID_ART_GR = e2.DataRowBaremes["ID_ART_GR"].ToString());
                    if (lignesArticleGratuit.Any() && (nbGratis.CompareTo(0, Globals.N_DEC_Q) > 0))
                    {
                        foreach (var ligne in lignesArticleGratuit.ToList().OrderByDescending(l => l.RECNO))
                        {
                            int new_row_index = billingEngine.AppendLine(ligne.DataRow);
                            DataRow drLigneGratuit = billingEngine.LIGNES.Rows[new_row_index];
                            billingEngine.RowIndexOfLastLine = billingEngine.LIGNES.Rows.Count - 1;
                            Api.DataRowMerge(drLigneGratuit, ligne.DataRow, false, new string[] { "DL_ID" }, false);
                            if ((ligne.Q).CompareTo(nbGratis, Globals.N_DEC_Q) > 0)
                            {
                                drLigneGratuit["Q"] = nbGratis;
                                nbGratis = 0;
                            }
                            else
                            {
                                nbGratis = nbGratis - (ligne.Q);
                                drLigneGratuit["Q"] = ligne.Q;
                            }
                            ligne.Q -= Convert.ToDouble(drLigneGratuit["Q"]);
                            drLigneGratuit["dl_id_gratuit"] = e.DataRowLignes["dl_id"];
                            drLigneGratuit["dl_id_parent"] = ligne.DL_ID;
                            drLigneGratuit["not_pr"] = true;
                            drLigneGratuit["pu"] = 0;
                            drLigneGratuit["remise"] = 0;
                            if (Globals.EngineBillingV.FieldListLignes.ContainsKey("REMISE2"))
                                drLigneGratuit["remise2"] = 0;
                            if (Globals.EngineBillingV.FieldListLignes.ContainsKey("REMISE3"))
                                drLigneGratuit["remise3"] = 0;
                            if (Globals.EngineBillingV.FieldListLignes.ContainsKey("REMISE4"))
                                drLigneGratuit["remise4"] = 0;

                            if (nbGratis.CompareTo(0, Globals.N_DEC_Q) <= 0)
                                break;
                        }
                    }
                }
                else
                {
                    Api.SmartReplace(e.DataRowLignes, "ID_ART_GR", "");
                }
                };
            billingEngine.BeforeQYGratuit += beforeQYGratuitEventHandler;
        }

        private void BillingEngine_BeforeBeforePaymentOrSave(object sender, BillingEngine.BeforeBeforePaymentOrSaveEventArgs e)
        {
            BillingEngine billingEngine = (BillingEngine) sender;
            billingEngine.ChangeAllPrices();
        }
    }
}