using EgtBEAMWALL.DataLayer.DatabaseModels;
using NLog;
using System;
using System.Collections.Generic;
using System.Linq;
using static EgtBEAMWALL.Core.ConstBeam;

namespace EgtBEAMWALL.DataLayer.Controllers
{
    public class ProdController : IDisposable
    {
        #region Public Constructors

        public ProdController()
        {
            Log.Info("ProdController instance Started");
        }

        #endregion Public Constructors

        #region Public Methods

        /// <summary>
        /// Aggiunta di un PROJ ad un PROD
        /// </summary>
        /// <param name="ProdId">ID Prod</param>
        /// <param name="ProjId">ID Proj</param>
        /// <param name="UserKey">User ID / Key number</param>
        /// <returns></returns>
        public bool AddProj(int ProdId, int ProjId, string UserKey = "USER01")
        {
            bool done = false;

            using (DatabaseContext localDbCtx = new DatabaseContext(DbConfig.CONNECTION_STRING))
            {
                // cerco Prod
                var currProd = localDbCtx
                                .ProdList
                                .Where(x => x.ProdId == ProdId)
                                .FirstOrDefault();

                // cerco Proj
                var currProj = localDbCtx
                                .ProjList
                                .Where(x => x.ProjId == ProjId)
                                .FirstOrDefault();

                // lo aggiorno
                currProj.ProdDbId = currProd.ProdDbId;
                currProj.Locked = true;
                currProj.LockDate = DateTime.Now;
                currProj.LockedBy = UserKey;

                // salvo
                localDbCtx.SaveChanges();
            }
            return done;
        }

        /// <summary>
        /// Delete Prod(+proj...) logically / on DB by ProdId
        /// </summary>
        /// <param name="ProjId"></param>
        /// <param name="IsLogical"></param>
        /// <returns></returns>
        public bool DeleteProd(int ProdId, bool IsLogical)
        {
            bool done = false;
            using (DatabaseContext localDbCtx = new DatabaseContext(DbConfig.CONNECTION_STRING))
            {
                var currProd = localDbCtx
                                .ProdList
                                .Where(x => x.ProdId == ProdId)
                                .SingleOrDefault();

                // procedo SOLO SE NON è stato prodotto (se è stato prodotto --> NON permetto la
                // cancellazione ed esco con false...)
                if (!currProd.IsProduced)
                {
                    // sel dei proj da aggiornare...
                    var proj2update = localDbCtx
                                        .ProjList
                                        .Where(x => x.ProdDbId == currProd.ProdDbId)
                                        .ToList();

                    // se richiesta cancellazione logica o cmq se fosse stato taggato come prodotto
                    if (IsLogical)
                    {
                        try
                        {
                            // segno eliminazione logica al/ai PROJ...
                            foreach (var item in proj2update)
                            {
                                item.IsActive = false;
                            }
                            // segno eliminazione logica al prod
                            currProd.IsActive = false;
                            // Commit changes
                            localDbCtx.SaveChanges();
                            done = true;
                        }
                        catch (Exception exc)
                        {
                            string errMessage = $"EXCEPTION on Prod.DeleteProd (logical only): {Environment.NewLine}{exc}";
                            Console.WriteLine(errMessage);
                            Log.Error(errMessage);
                        }
                    }
                    else
                    {
                        // sel dei MachGroup da prod
                        var machGroup2del = localDbCtx
                                            .MachGroupList
                                            .Where(x => x.ProdDbId == currProd.ProdDbId)
                                            .ToList();

                        // selezione dei part da machgroup
                        var part2del = localDbCtx
                                        .PartList
                                        .Where(x => x.MachGroup.ProdDbId == currProd.ProdDbId)
                                        .ToList();
                        try
                        {
                            // update proj...
                            foreach (var item in proj2update)
                            {
                                item.ProdDbId = null;
                            }
                            // remove from database
                            localDbCtx.PartList.RemoveRange(part2del);
                            //// salvo
                            //localDbCtx.SaveChanges();
                            localDbCtx.MachGroupList.RemoveRange(machGroup2del);
                            //// salvo
                            //localDbCtx.SaveChanges();
                            localDbCtx.ProdList.Remove(currProd);
                            // salvo
                            localDbCtx.SaveChanges();
                            done = true;
                        }
                        catch (Exception exc)
                        {
                            string errMessage = $"EXCEPTION on Prod.DeleteProd: {Environment.NewLine}{exc}";
                            Console.WriteLine(errMessage);
                            Log.Error(errMessage);
                        }
                    }
                }
            }
            return done;
        }

        public void Dispose()
        {
        }

        /// <summary>
        /// Get record by ProdDbId
        /// </summary>
        /// <param name="ProdDbId"></param>
        /// <returns></returns>
        public ProdModel FindByProdDbId(int ProdDbId)
        {
            ProdModel answ;
            using (DatabaseContext localDbCtx = new DatabaseContext(DbConfig.CONNECTION_STRING))
            {
                answ = localDbCtx
                .ProdList
                .Where(x => x.ProdDbId == ProdDbId)
                .SingleOrDefault();
            }
            return answ;
        }

        /// <summary>
        /// Get record by ProdId
        /// </summary>
        /// <param name="ProdId"></param>
        /// <returns></returns>
        public ProdModel FindByProdId(int ProdId)
        {
            ProdModel answ;
            using (DatabaseContext localDbCtx = new DatabaseContext(DbConfig.CONNECTION_STRING))
            {
                answ = localDbCtx
                .ProdList
                .Where(x => x.ProdId == ProdId)
                .SingleOrDefault();
            }
            return answ;
        }

        /// <summary>
        /// Get record by ProdId ass Core.ProdFileM
        /// </summary>
        /// <param name="ProdId"></param>
        /// <returns></returns>
        public Core.ProdFileM FindCoreByProdId(int ProdId)
        {
            var currProd = FindByProdId(ProdId);
            if (currProd == null)
            {
                return null;
            }
            return Core.ProdFileM.CreateProdFileM(currProd.ProdId, ProjIdByProd(ProdId), currProd.DtCreated, currProd.Description, currProd.PType, currProd.Machine, currProd.LockedBy, currProd.LockDate, currProd.IsActive, currProd.IsProduced, currProd.IsArchived);
        }

        /// <summary>
        /// Elenco prod
        /// </summary>
        /// <param name="numRecord">Num max record da recuperare</param>
        /// <param name="OnlyActive">Solo con ALMENO 1 PROJ attivo (senza cancellazione logica)</param>
        /// <param name="ShowArchived">Se true: mostra anche archiviati (default li nasconde)</param>
        /// <returns></returns>
        public List<Core.ProdFileM> GetLastDesc(int numRecord, bool OnlyActive, bool ShowArchived = false)
        {
            List<Core.ProdFileM> result = new List<Core.ProdFileM>();
            //List<ProdModel> dbResult = GetLastDbModelDesc(numRecord);
            List<ProdModel> dbResult = new List<ProdModel>();
            using (DatabaseContext localDbCtx = new DatabaseContext(DbConfig.CONNECTION_STRING))
            {
                // se numRecord = 0 --> passo tutti
                if (numRecord == 0)
                {
                    numRecord = localDbCtx.ProdList.Count();
                }
                // retrieve
                dbResult = localDbCtx
                    .ProdList
                    .Where(x => (!x.IsArchived || ShowArchived))
                    // condizione join sui PROJ
                    .Join(localDbCtx.ProjList.Where(x => x.IsActive || !OnlyActive),
                        p => p.ProdDbId,
                        e => e.ProdDbId,
                        (p, e) => p)
                    .Distinct()
                    .OrderByDescending(x => x.ProdId)
                    .Take(numRecord)
                    .ToList();
            }

            // conversione
            result = dbResult.Select(x => Core.ProdFileM.CreateProdFileM(x.ProdId, ProjIdByProd(x.ProdId), x.DtCreated, x.Description, x.PType, x.Machine, x.LockedBy, x.LockDate, x.IsActive, x.IsProduced, x.IsArchived)).ToList();
            return result;
        }

        /// <summary>
        /// Elenco prod
        /// </summary>
        /// <param name="dtStart">Inizio periodo estrazione</param>
        /// <param name="dtEnd">Fine periodo estrazione</param>
        /// <param name="numRecord">Num max record da recuperare</param>
        /// <param name="OnlyActive">Solo con ALMENO 1 PROJ attivo (senza cancellazione logica)</param>
        /// <param name="ShowArchived">Se true: mostra anche archiviati (default li nasconde)</param>
        /// <returns></returns>
        public List<Core.ProdFileM> GetLastDesc(DateTime dtStart, DateTime dtEnd, int numRecord, bool OnlyActive, bool ShowArchived = false)
        {
            List<Core.ProdFileM> result = new List<Core.ProdFileM>();
            //List<ProdModel> dbResult = GetLastDbModelDesc(numRecord);
            List<ProdModel> dbResult = new List<ProdModel>();
            using (DatabaseContext localDbCtx = new DatabaseContext(DbConfig.CONNECTION_STRING))
            {
                // se numRecord = 0 --> passo tutti
                if (numRecord == 0)
                {
                    numRecord = localDbCtx.ProdList.Count();
                }
                // retrieve
                dbResult = localDbCtx
                    .ProdList
                    .Where(x => x.DtCreated >= dtStart && x.DtCreated <= dtEnd && (!x.IsArchived || ShowArchived))
                    // condizione join sui PROJ
                    .Join(localDbCtx.ProjList.Where(x => x.IsActive || !OnlyActive),
                        p => p.ProdDbId,
                        e => e.ProdDbId,
                        (p, e) => p)
                    .Distinct()
                    .OrderByDescending(x => x.ProdId)
                    .Take(numRecord)
                    .ToList();
            }

            // conversione
            result = dbResult.Select(x => Core.ProdFileM.CreateProdFileM(x.ProdId, ProjIdByProd(x.ProdId), x.DtCreated, x.Description, x.PType, x.Machine, x.LockedBy, x.LockDate, x.IsActive, x.IsProduced, x.IsArchived)).ToList();
            return result;
        }

        /// <summary>
        /// Fornisce nuovo indice VUOTO da usare (allocando sul DB)
        /// </summary>
        /// <param name="ProjId">ID Proj</param>
        /// <param name="UserKey">User ID / Key number</param>
        /// <returns></returns>
        public int GetNextIndex(int ProjId, string UserKey = "USER01")
        {
            int nextId = 0;

            using (DatabaseContext localDbCtx = new DatabaseContext(DbConfig.CONNECTION_STRING))
            {
                // cerco se ne ho ALMENO 1....
                var numRec = localDbCtx.ProdList.Count();
                if (numRec == 0)
                {
                    nextId = 1;
                }
                else
                {
                    // retrieve ultimo...
                    var maxRecord = localDbCtx
                        .ProdList
                        .OrderByDescending(x => x.ProdId)
                        .Take(1)
                        .FirstOrDefault();
                    // incremento
                    nextId = maxRecord.ProdId + 1;
                }

                // creo nuovo PROD...
                var newProd = localDbCtx
                    .ProdList
                    .Add(new ProdModel() { ProdId = nextId, Locked = true, DtCreated = DateTime.Now });

                // cerco Proj
                var currProj = localDbCtx
                    .ProjList
                    .Where(x => x.ProjId == ProjId)
                    .FirstOrDefault();

                // aggiungo proj-prod
                currProj.ProdDbId = newProd.ProdDbId;
                currProj.Locked = true;
                currProj.LockDate = DateTime.Now;
                currProj.LockedBy = UserKey;

                // Commit changes
                localDbCtx.SaveChanges();
            }
            return nextId;
        }

        /// <summary>
        /// Verifica prod assegnato a supervisor: ...se c'e' anche un solo machgroup del prod
        /// assegnato ad un supervisor o in stato 0 (dovrebbe essere la stessa cosa?)
        /// </summary>
        /// <param name="ProdId"></param>
        /// <returns></returns>
        public bool IsAnyInSupervisor(int ProdId)
        {
            int numAssigned = 0;
            using (DatabaseContext localDbCtx = new DatabaseContext(DbConfig.CONNECTION_STRING))
            {
                // cerco se ci siano assegnati a supervisor
                numAssigned = localDbCtx
                                .MachGroupList
                                .Where(x => x.Prod.ProdId == ProdId && (!string.IsNullOrEmpty(x.SupervisorId) || x.State >= 0))
                                .Count();
            }
            return numAssigned > 0;
        }

        /// <summary> Return Lock by ProdId (proj & prod) </summary> <param name="ProdId"></param> <returns></returns>
        public bool IsLockByProdId(int ProdId)
        {
            bool bIsLock = false;
            using (DatabaseContext localDbCtx = new DatabaseContext(DbConfig.CONNECTION_STRING))
            {
                // seleziono il prod...
                var currProd = localDbCtx
                                .ProdList
                                .Where(x => x.ProdId == ProdId)
                                .FirstOrDefault();

                if (currProd != null)
                {
                    bIsLock = currProd.Locked;

                    var currProj = localDbCtx
                        .ProjList
                        .Where(x => x.ProdDbId == currProd.ProdDbId)
                        .ToList();

                    if (currProj != null && !bIsLock)
                    {
                        bIsLock = currProj.Any(x => x.Locked);
                    }
                }
            }
            return bIsLock;
        }

        /// <summary> Manage Lock by ProdId (proj & prod) </summary> <param name="ProdId"></param>
        /// <param name="Locked">Stato Lock da impostare</param> <param name="UserKey">User ID / Key
        /// number</param> <returns></returns>
        public ProdModel LockByProdId(int ProdId, bool Locked, string UserKey = "USER01")
        {
            ProdModel currProd;
            // seleziono il prod...
            using (DatabaseContext localDbCtx = new DatabaseContext(DbConfig.CONNECTION_STRING))
            {
                currProd = localDbCtx
                            .ProdList
                            .Where(x => x.ProdId == ProdId)
                            .SingleOrDefault();

                if (currProd != null)
                {
                    currProd.Locked = Locked;
                    currProd.LockDate = DateTime.Now;
                    currProd.LockedBy = Locked ? UserKey : "";
                    localDbCtx.Entry(currProd).State = System.Data.Entity.EntityState.Modified;

                    var currProj = localDbCtx
                        .ProjList
                        .Where(x => x.ProdDbId == currProd.ProdDbId)
                        .ToList();

                    //currProj.ForEach(x => x.Locked = Locked);
                    foreach (var item in currProj)
                    {
                        item.Locked = Locked;
                        item.LockDate = DateTime.Now;
                        item.LockedBy = Locked ? UserKey : "";
                        localDbCtx.Entry(item).State = System.Data.Entity.EntityState.Modified;
                    }
                }

                localDbCtx.SaveChanges();
            }
            return currProd;
        }

        /// <summary>
        /// Reinizializzaizone del controller
        /// </summary>
        public void ResetController()
        {
        }

        /// <summary>
        /// Update single PROD
        /// </summary>
        /// <param name="updItem"></param>
        /// <returns></returns>
        public bool Update(ProdModel updItem)
        {
            bool done = false;
            using (DatabaseContext localDbCtx = new DatabaseContext(DbConfig.CONNECTION_STRING))
            {
                try
                {
                    var item2update = localDbCtx
                                        .ProdList
                                        .Where(x => x.ProdDbId == updItem.ProdDbId)
                                        .SingleOrDefault();

                    if (item2update != null)
                    {
                        // update, vers 1...
                        localDbCtx.Entry(item2update).CurrentValues.SetValues(updItem);

                        //// update, vers 2
                        //localDbCtx.PartList.Remove(item2del);
                        //localDbCtx.PartList.Add(updItem);

                        // Commit changes
                        localDbCtx.SaveChanges();
                        done = true;
                    }
                    else
                    {
                        string errMessage = $"ERROR on Prod.Update: req item was not found | ProdId {updItem.ProdId} | ProdDbId {updItem.ProdDbId} | Description {updItem.Description}";
                        Console.WriteLine(errMessage);
                        Log.Error(errMessage);
                    }
                }
                catch (Exception exc)
                {
                    string errMessage = $"EXCEPTION on Prod.Update: {Environment.NewLine}{exc}";
                    Console.WriteLine(errMessage);
                    Log.Error(errMessage);
                }
            }
            return done;
        }

        /// <summary>
        /// Update record su DB x campo IsArchived
        /// </summary>
        /// <param name="ProdId"></param>
        /// <param name="IsArchived"></param>
        /// <returns></returns>
        public bool UpdateArchived(int ProdId, bool IsArchived)
        {
            bool fatto = false;
            // cerco specifico Prod
            ProdModel currData = new ProdModel();
            using (DatabaseContext localDbCtx = new DatabaseContext(DbConfig.CONNECTION_STRING))
            {
                currData = localDbCtx
                               .ProdList
                               .Where(x => x.ProdId == ProdId)
                               .SingleOrDefault();
                if (currData != null)
                {
                    // sel dei proj da aggiornare...
                    var proj2update = localDbCtx
                                        .ProjList
                                        .Where(x => x.ProdDbId == currData.ProdDbId)
                                        .ToList();
                    try
                    {
                        // aggiorno valore descrizione
                        currData.IsArchived = IsArchived;

                        // update dei proj relativi
                        foreach (var item in proj2update)
                        {
                            item.IsArchived = IsArchived;
                        }

                        // Commit changes
                        localDbCtx.SaveChanges();
                    }
                    catch (Exception exc)
                    {
                        string errMessage = $"EXCEPTION on Prod.UpdateArchived:{Environment.NewLine}{exc}";
                        Console.WriteLine(errMessage);
                        Log.Error(errMessage);
                    }
                }
                else
                {
                    string errMessage = $"ERROR on Prod.UpdateArchived: req item was not found | ProdId {ProdId} | IsArchived {IsArchived}";
                    Console.WriteLine(errMessage);
                    Log.Error(errMessage);
                }
            }
            return fatto;
        }

        /// <summary>
        /// Update record su DB x Description
        /// </summary>
        /// <param name="ProdId"></param>
        /// <param name="Description"></param>
        /// <returns></returns>
        public bool UpdateDescription(int ProdId, string Description)
        {
            bool fatto = false;
            // cerco specifico Prod
            ProdModel currData = new ProdModel();
            using (DatabaseContext localDbCtx = new DatabaseContext(DbConfig.CONNECTION_STRING))
            {
                currData = localDbCtx
                               .ProdList
                               .Where(x => x.ProdId == ProdId)
                               .SingleOrDefault();
                if (currData != null)
                {
                    try
                    {
                        // aggiorno valore descrizione
                        currData.Description = Description;

                        // Commit changes
                        localDbCtx.SaveChanges();
                    }
                    catch (Exception exc)
                    {
                        string errMessage = $"EXCEPTION on Prod.UpdateDescription:{Environment.NewLine}{exc}";
                        Console.WriteLine(errMessage);
                        Log.Error(errMessage);
                    }
                }
                else
                {
                    string errMessage = $"ERROR on Prod.UpdateDescription: req item was not found | ProdId {ProdId} | Description {Description}";
                    Console.WriteLine(errMessage);
                    Log.Error(errMessage);
                }
            }
            return fatto;
        }

        /// <summary>
        /// Update record su DB x elenco MachGroup:
        /// - NON vengono eliminati record (se ce ne son altri sul DB non saranno toccati)
        /// - i record ESISTENTI (per MachGroup.ID) saranno aggiornati (tranne start/end/status)
        /// - i record NON ESISTENTI (per MachGroup.ID) saranno AGGIUNTI (tranne start/end/status)
        /// </summary>
        /// <param name="ProdId">Id del Prod</param>
        /// <param name="MachGroupList">Elenco MachGroup da associare</param>
        /// <returns>Bool esecuzione con successo o meno</returns>
        public bool UpdateMachGroup(int ProdId, List<Core.MyMachGroupM> MachGroupList)
        {
            bool testOk = false;
            // calcolo occorrenze x ogni ID della barra...
            var listaCheck = MachGroupList
                                .GroupBy(x => x.Id)
                                .Select(n => new
                                {
                                    PartId = n.Key,
                                    PartCount = n.Count()
                                })
                                .OrderBy(n => n.PartCount);

            // controllo: nell'elenco delle barre MachGroupList NON devono esserci duplicati per
            // l'ID (esterno) che deve essere univoco...
            testOk = listaCheck.Where(x => x.PartCount > 1).Count() == 0;
            if (testOk)
            {
                ProdModel currData = new ProdModel();
                using (DatabaseContext localDbCtx = new DatabaseContext(DbConfig.CONNECTION_STRING))
                {
                    var myStatusMapCtrl = new StatusMapController();
                    try
                    {
                        // Recupero il PROD nel contesto DB attuale
                        currData = localDbCtx
                                    .ProdList
                                    .Where(x => x.ProdId == ProdId)
                                    .SingleOrDefault();

                        if (currData != null)
                        {
                            // preparo elenco
                            List<MachGroupModel> itemsMG2Add = new List<MachGroupModel>();

                            List<Core.MyMachGroupM> MachGroupList2Add = new List<Core.MyMachGroupM>();
                            List<PartModel> PartList2Add = new List<PartModel>();
                            List<PartModel> PartList2Rem = new List<PartModel>();
                            var logMGCtrl = new MachGroupController();
                            // cerco le MG esistenti --> aggiorno
                            foreach (var item in MachGroupList)
                            {
                                var currMG = logMGCtrl.FindByMachGroupId(ProdId, item.Id);
                                var convCurrMG = logMGCtrl.ConvertFromCore(item, currData.ProdDbId);
                                if (currMG != null)
                                {
                                    // se non identico x equality limitata a ViewOptim...
                                    if (!currMG.ViewOptimEquals(convCurrMG))
                                    {
                                        // aggiorno con nuovi valori ricevuti
                                        currMG.H = convCurrMG.H;
                                        currMG.L = convCurrMG.L;
                                        currMG.W = convCurrMG.W;
                                        currMG.Material = convCurrMG.Material;
                                        currMG.Name = convCurrMG.Name;
                                        // salvo
                                        localDbCtx.SaveChanges();
                                        // registro modifica StatusMap
                                        myStatusMapCtrl.UpdateAction(currMG.SupervisorId, ProdId, currMG.MachGroupId, Core.StatusMapItemType.MachGroup, Core.StatusMapOpType.MachGroupMod, "");
                                    }
                                }
                                else
                                {
                                    itemsMG2Add.Add(convCurrMG);
                                    // registro modifica StatusMap
                                    myStatusMapCtrl.UpdateAction("", ProdId, item.Id, Core.StatusMapItemType.MachGroup, Core.StatusMapOpType.MachGroupAdd, "");
                                }
                            }
                            // aggiungo MachGroup
                            localDbCtx.MachGroupList.AddRange(itemsMG2Add);
                            // Commit changes
                            localDbCtx.SaveChanges();

                            // verifico di nuovo l'elenco delle MG x le relative PART...
                            foreach (var item in MachGroupList)
                            {
                                var currMG = logMGCtrl.FindByMachGroupId(ProdId, item.Id);
                                int MachGroupDbId = currMG.MachGroupDbId;
                                bool modMg = false;
                                // 2023.05.10: recupero TUTTE le part del MachGroup e poi lavoro...
                                var currMgPartList = localDbCtx
                                                  .PartList
                                                  .Where(x => x.MachGroup.Prod.ProdId == ProdId && x.MachGroup.MachGroupId == item.Id)
                                                  .ToList();
                                // preparo elenco PartList x eventuale rimozione
                                var currPartList2Rem = new List<PartModel>();
                                currPartList2Rem.AddRange(currMgPartList);
                                // verifico se uguali o meno...
                                foreach (var currPartM in item.PartMList)
                                {
                                    var myPartCtrl = new PartController();
                                    var currPart = currMgPartList
                                                      .Where(x => x.PartId == currPartM.nPartId)
                                                      .SingleOrDefault();
                                    var convCurrPartM = myPartCtrl.ConvertFromCore(currPartM, MachGroupDbId);
                                    if (currPart != null)
                                    {
                                        // se non identico x equality limitata a ViewOptim...
                                        if (!currPart.ViewOptimEquals(convCurrPartM))
                                        {
                                            // aggiorno con nuovi valori ricevuti
                                            currPart.H = convCurrPartM.H;
                                            currPart.L = convCurrPartM.L;
                                            currPart.W = convCurrPartM.W;
                                            currPart.Material = convCurrPartM.Material;
                                            currPart.CALC_State = convCurrPartM.CALC_State;
                                            currPart.ROT = convCurrPartM.ROT;
                                            currPart.PDN = convCurrPartM.PDN;
                                            currPart.NAM = convCurrPartM.NAM;
                                            // aggiorno anche il BtlPartId
                                            currPart.BTLPartDbId = convCurrPartM.BTLPartDbId;
                                            // salvo
                                            localDbCtx.SaveChanges();
                                            modMg = true;
                                        }
                                        // tolgo da elenco di rimozione...
                                        currPartList2Rem.Remove(currPart);
                                    }
                                    else
                                    {
                                        PartList2Add.Add(convCurrPartM);
                                        modMg = true;
                                    }
                                }
                                // verifico se salvare...
                                if (modMg)
                                {
                                    myStatusMapCtrl.UpdateAction(currMG.SupervisorId, ProdId, currMG.MachGroupId, Core.StatusMapItemType.MachGroup, Core.StatusMapOpType.MachGroupMod, "");
                                }

                                // aggiungo le part esistenti nel MG non ricevute...
                                PartList2Rem.AddRange(currPartList2Rem);
                            }
                            // elimino parti da rimuovere..
                            localDbCtx.PartList.RemoveRange(PartList2Rem);
                            // aggiungo PartList
                            localDbCtx.PartList.AddRange(PartList2Add);
                            // Commit changes
                            localDbCtx.SaveChanges();

                            // sel dei MachGroup da prod OLD
                            List<MachGroupModel> itemsMGOld = localDbCtx
                                .MachGroupList
                                .Where(x => x.Prod.ProdId == ProdId)
                                .ToList();
                            // elenco degli ID del MachGroup NON trovati
                            List<int> MgId2rem = itemsMGOld.Select(x => x.MachGroupId).Except(MachGroupList.Select(y => y.Id)).ToList();
                            // processo i MachGroup eliminati
                            foreach (var item in MgId2rem)
                            {
                                logMGCtrl.Delete(ProdId, item);
                            }

                            // aggiorno valore isNew a false x PROD
                            currData.IsNew = false;

                            // Commit changes
                            localDbCtx.SaveChanges();
                        }
                        else
                        {
                            string errMessage = $"ERROR on Prod.UpdateMachGroup: req item was not found | ProdId {ProdId} | MachGroupList {MachGroupList.Count} rec";
                            Console.WriteLine(errMessage);
                            Log.Error(errMessage);
                        }
                    }
                    catch (Exception exc)
                    {
                        string errMessage = $"EXCEPTION on Prod.UpdateMachGroup: {Environment.NewLine}{exc}";
                        Console.WriteLine(errMessage);
                        Log.Error(errMessage);
                    }
                }
            }
            return testOk;
        }

        /// <summary>
        /// Update record su DB x PType
        /// </summary>
        /// <param name="ProdId"></param>
        /// <param name="Machine"></param>
        /// <returns></returns>
        public Core.ProdFileM UpdateMachine(int ProdId, String Machine)
        {
            ProdModel currData = new ProdModel();
            using (DatabaseContext localDbCtx = new DatabaseContext(DbConfig.CONNECTION_STRING))
            {
                try
                {
                    currData = localDbCtx
                            .ProdList
                            .Where(x => x.ProdId == ProdId)
                            .SingleOrDefault();
                    if (currData != null)
                    {
                        // aggiorno valore BTL
                        currData.Machine = Machine;

                        // Commit changes
                        localDbCtx.SaveChanges();
                    }
                    else
                    {
                        string errMessage = $"ERROR on Prod.UpdateMachine: req item was not found | ProdId {ProdId} | Machine {Machine}";
                        Console.WriteLine(errMessage);
                        Log.Error(errMessage);
                    }
                }
                catch (Exception exc)
                {
                    string errMessage = $"EXCEPTION on Prod.UpdateMachine: {Environment.NewLine}{exc}";
                    Console.WriteLine(errMessage);
                    Log.Error(errMessage);
                }
            }
            return coreConv(currData);
        }

        /// <summary>
        /// Update record su DB x PType
        /// </summary>
        /// <param name="ProdId"></param>
        /// <param name="PType"></param>
        /// <returns></returns>
        public Core.ProdFileM UpdatePType(int ProdId, BWType PType)
        {
            ProdModel currData = new ProdModel();
            using (DatabaseContext localDbCtx = new DatabaseContext(DbConfig.CONNECTION_STRING))
            {
                try
                {
                    currData = localDbCtx
                            .ProdList
                            .Where(x => x.ProdId == ProdId)
                            .SingleOrDefault();
                    if (currData != null)
                    {
                        // aggiorno valore BTL
                        currData.PType = PType;

                        // Commit changes
                        localDbCtx.SaveChanges();
                    }
                    else
                    {
                        string errMessage = $"ERROR on Prod.UpdatePType: req item was not found | ProdId {ProdId} | PType {PType}";
                        Console.WriteLine(errMessage);
                        Log.Error(errMessage);
                    }
                }
                catch (Exception exc)
                {
                    string errMessage = $"EXCEPTION on Prod.UpdatePType: {Environment.NewLine}{exc}";
                    Console.WriteLine(errMessage);
                    Log.Error(errMessage);
                }
            }
            return coreConv(currData);
        }

        /// <summary> Return User Code/Key that Locks by ProdId (proj & prod) </summary> <param
        /// name="ProdId"></param> <returns></returns>
        public string UserLockByProdId(int ProdId)
        {
            string LockBy = "";
            using (DatabaseContext localDbCtx = new DatabaseContext(DbConfig.CONNECTION_STRING))
            {
                try
                {
                    // seleziono il prod...
                    var currProd = localDbCtx
                                .ProdList
                                .Where(x => x.ProdId == ProdId)
                                .FirstOrDefault();

                    if (currProd != null)
                    {
                        LockBy = currProd.LockedBy;

                        var currProj = localDbCtx
                            .ProjList
                            .Where(x => x.ProdDbId == currProd.ProdDbId)
                            .ToList();

                        if (currProj != null && string.IsNullOrEmpty(LockBy))
                        {
                            LockBy = currProj.FirstOrDefault(x => !string.IsNullOrEmpty(x.LockedBy)).LockedBy;
                        }
                    }
                    else
                    {
                        string errMessage = $"ERROR on Prod.UserLockByProdId: req item was not found | ProdId {ProdId}";
                        Console.WriteLine(errMessage);
                        Log.Error(errMessage);
                    }
                }
                catch (Exception exc)
                {
                    string errMessage = $"EXCEPTION on Prod.UserLockByProdId: {Environment.NewLine}{exc}";
                    Console.WriteLine(errMessage);
                    Log.Error(errMessage);
                }
            }
            return LockBy;
        }

        #endregion Public Methods

        #region Protected Methods

        /// <summary>
        /// Helper conversione modelli
        /// </summary>
        /// <param name="currProd"></param>
        /// <returns></returns>
        protected Core.ProdFileM coreConv(ProdModel currProd)
        {
            Core.ProdFileM answ = Core.ProdFileM.CreateProdFileM(currProd.ProdId, ProjIdByProd(currProd.ProdId), currProd.DtCreated, currProd.Description, currProd.PType, currProd.Machine, currProd.LockedBy, currProd.LockDate, currProd.IsActive, currProd.IsProduced, currProd.IsArchived);
            return answ;
        }

        protected List<int> ProjIdByProd(int ProdId)
        {
            var ProjCtr = new ProjController();
            return ProjCtr.GetByProdAsc(ProdId).Select(y => y.nProjId).ToList();
            //return DbManager.obj.ProjCtr.GetByProdAsc(ProdId).Select(y => y.nProjId).ToList();
        }

        #endregion Protected Methods

        #region Private Fields

        /// <summary>
        /// Istanza logger
        /// </summary>
        private NLog.Logger Log = LogManager.GetCurrentClassLogger();

        #endregion Private Fields

        #region Private Methods

        /// <summary>
        /// Update record su DB x campo IsProduced lasciato private se servisse in futuro x ora NON
        /// esposto e fatto implicitamente in StatusMapController.StartProd
        /// </summary>
        /// <param name="ProdId"></param>
        /// <param name="IsProduced"></param>
        /// <returns></returns>
        private bool UpdateProduced(int ProdId, bool IsProduced)
        {
            bool fatto = false;
            // cerco specifico Prod
            ProdModel currData = new ProdModel();
            using (DatabaseContext localDbCtx = new DatabaseContext(DbConfig.CONNECTION_STRING))
            {
                currData = localDbCtx
                               .ProdList
                               .Where(x => x.ProdId == ProdId)
                               .SingleOrDefault();
                if (currData != null)
                {
                    try
                    {
                        // aggiorno valore descrizione
                        currData.IsProduced = IsProduced;

                        // Commit changes
                        localDbCtx.SaveChanges();
                    }
                    catch (Exception exc)
                    {
                        string errMessage = $"EXCEPTION on Prod.UpdateProduced:{Environment.NewLine}{exc}";
                        Console.WriteLine(errMessage);
                        Log.Error(errMessage);
                    }
                }
                else
                {
                    string errMessage = $"ERROR on Prod.UpdateProduced: req item was not found | ProdId {ProdId} | IsProduced {IsProduced}";
                    Console.WriteLine(errMessage);
                    Log.Error(errMessage);
                }
            }
            return fatto;
        }

        #endregion Private Methods
    }
}