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 ProjController : IDisposable
    {
        #region Public Constructors

        public ProjController()
        {
        }

        #endregion Public Constructors

        #region Public Methods

        /// <summary>
        /// Search for already imported BTL from FileName (only)
        /// =0 : NOT found &gt;0 : ProjId (already present) for overwrite
        /// </summary>
        /// <param name="BTLFileName"></param>
        /// <returns></returns>
        public int AlreadyImported(string BTLFileName)
        {
            int answ = 0;
            using (DatabaseContext localDbCtx = new DatabaseContext(DbConfig.CONNECTION_STRING))
            {
                var dbResult = localDbCtx
                       .ProjList
                       .Where(x => x.BTLFileName == BTLFileName)
                       .FirstOrDefault();

                //se avesse trovato-- > riporto id...
                if (dbResult != null && dbResult.ProjId > 0)
                {
                    answ = dbResult.ProjId;
                }
            }
            return answ;
        }

        /// <summary>
        /// Delete Proj logically / on DB by ProjId
        /// </summary>
        /// <param name="ProjId"></param>
        /// <param name="IsLogical"></param>
        /// <returns></returns>
        public bool DeleteProj(int ProjId, bool IsLogical)
        {
            bool done = false;

            using (DatabaseContext localDbCtx = new DatabaseContext(DbConfig.CONNECTION_STRING))
            {
                var currProj = localDbCtx
                                .ProjList
                                .Where(x => x.ProjId == ProjId)
                                .SingleOrDefault();

                if (IsLogical)
                {
                    try
                    {
                        currProj.IsActive = false;
                        // Commit changes
                        localDbCtx.SaveChanges();
                        done = true;
                    }
                    catch (Exception exc)
                    {
                        string errMessage = $"EXCEPTION on Proj.DeleteProj (logical only): {Environment.NewLine}{exc}";
                        Console.WriteLine(errMessage);
                        Log.Error(errMessage);
                    }
                }
                else
                {
                    // sel delle BTLParts da proj
                    var parts2del = localDbCtx
                                        .BTLPartList
                                        .Where(x => x.ProjDbId == currProj.ProjDbId);

                    try
                    {
                        // remove from database
                        localDbCtx.BTLPartList.RemoveRange(parts2del);
                        localDbCtx.ProjList.Remove(currProj);
                        // Commit changes
                        localDbCtx.SaveChanges();
                        done = true;
                    }
                    catch (Exception exc)
                    {
                        string errMessage = $"EXCEPTION on Proj.DeleteProj (on DB): {Environment.NewLine}{exc}";
                        Console.WriteLine(errMessage);
                        Log.Error(errMessage);
                    }
                }
            }
            return done;
        }

        public void Dispose()
        {
        }

        /// <summary>
        /// Get records filtered by BtlPartName matching regexp BtlFileName[_number]
        /// </summary>
        /// <param name="BtlFileName">Base name to search for (=starts by BtlFileName%)</param>
        /// <param name="OnlyActive">Solo i record attivi (senza cancellazione logica)</param>
        /// <returns></returns>
        public List<ProjModel> FindByBtlFileName(string BtlFileName, bool OnlyActive)
        {
            List<ProjModel> searchResult = new List<ProjModel>();
            using (DatabaseContext localDbCtx = new DatabaseContext(DbConfig.CONNECTION_STRING))
            {
                // in primi cerco il record "parent" generale, se non ci fosse inutile proseguire...
                ProjModel parentRec = localDbCtx
                        .ProjList
                        .Where(x => x.BTLFileName == BtlFileName && (!OnlyActive || x.IsActive))
                        .FirstOrDefault();
                if (parentRec != null && parentRec.ProjId > 0)
                {
                    // inserisco nei risultati
                    searchResult.Add(parentRec);
                    // cerco eventuali dati "child" puliti
                    var childRec = localDbCtx
                            .ProjList
                            .Where(x => x.BTLFileName.StartsWith(BtlFileName + "_") && (!OnlyActive || x.IsActive))
                            .ToList();
                    // faccio filtro con ricerca regexp x scartare "falsi positivi" come BtlFileName_nonNumero...
                    if (childRec.Count > 0)
                    {
                        // ciclo nei risultati x verificare se si tratti di PURO NUMERO...
                        foreach (var item in childRec)
                        {
                            string maybeNumber = item.BTLFileName.Replace($"{BtlFileName}_", "");
                            int index = 0;
                            bool isNumber = int.TryParse(maybeNumber, out index);
                            if (isNumber)
                            {
                                searchResult.Add(item);
                            }
                        }
                    }
                }
            }
            return searchResult;
        }

        /// <summary>
        /// Get record by ProjDbId
        /// </summary>
        /// <param name="ProjDbId"></param>
        /// <returns></returns>
        public ProjModel FindByProjDbId(int ProjDbId)
        {
            ProjModel answ;
            using (DatabaseContext localDbCtx = new DatabaseContext(DbConfig.CONNECTION_STRING))
            {
                answ = localDbCtx
                        .ProjList
                        .Where(x => x.ProjDbId == ProjDbId)
                        .SingleOrDefault();
            }
            return answ;
        }

        /// <summary>
        /// Get record by ProjId
        /// </summary>
        /// <param name="ProjId"></param>
        /// <returns></returns>
        public ProjModel FindByProjId(int ProjId)
        {
            ProjModel answ;
            using (DatabaseContext localDbCtx = new DatabaseContext(DbConfig.CONNECTION_STRING))
            {
                answ = localDbCtx
               .ProjList
                .Where(x => x.ProjId == ProjId)
                .SingleOrDefault();
            }
            return answ;
        }

        /// <summary>
        /// Get record by ProjId converted
        /// </summary>
        /// <param name="ProjId"></param>
        /// <returns></returns>
        public Core.ProjFileM FindByProjIdConv(int ProjId)
        {
            return coreConv(FindByProjId(ProjId));
        }

        /// <summary>
        /// Get filtered data by ProdId (ASC ordered)
        /// </summary>
        /// <param name="ProdId"></param>
        /// <returns></returns>
        public List<Core.ProjFileM> GetByProdAsc(int ProdId)
        {
            List<Core.ProjFileM> answ = new List<Core.ProjFileM>();
            int ProdDbId = 0;
            using (DatabaseContext localDbCtx = new DatabaseContext(DbConfig.CONNECTION_STRING))
            {
                try
                {
                    var currProd = localDbCtx
                        .ProdList
                        .Where(x => x.ProdId == ProdId)
                        .FirstOrDefault();
                    if (currProd != null)
                    {
                        ProdDbId = currProd.ProdDbId;
                    }
                }
                catch (Exception exc)
                {
                    string errMessage = $"EXCEPTION on Proj.GetByProdAsc: {Environment.NewLine}{exc}";
                    Console.WriteLine(errMessage);
                    Log.Error(errMessage);
                }
                // retrieve
                var dbRes = localDbCtx
                    .ProjList
                    .Where(x => x.ProdDbId == ProdDbId)
                    .OrderBy(x => x.ProdDbId)
                    .ToList();
                // conversione
                answ = dbRes.Select(x => coreConv(x)).ToList();
            }
            return answ;
        }

        /// <summary>
        /// Get filtered data by ProdId (DESC ordered)
        /// </summary>
        /// <param name="ProdDbId"></param>
        /// <returns></returns>
        public List<Core.ProjFileM> GetByProdDesc(int ProdId)
        {
            List<Core.ProjFileM> answ = new List<Core.ProjFileM>();
            int ProdDbId = 0;
            using (DatabaseContext localDbCtx = new DatabaseContext(DbConfig.CONNECTION_STRING))
            {
                try
                {
                    var currProd = localDbCtx
                                    .ProdList
                                    .Where(x => x.ProdId == ProdId)
                                    .FirstOrDefault();
                    if (currProd != null)
                    {
                        ProdDbId = currProd.ProdDbId;
                    }
                }
                catch (Exception exc)
                {
                    string errMessage = $"EXCEPTION on Proj.GetByProdDesc: {Environment.NewLine}{exc}";
                    Console.WriteLine(errMessage);
                    Log.Error(errMessage);
                }
                // retrieve
                var dbRes = localDbCtx
                            .ProjList
                            .Where(x => x.ProdDbId == ProdDbId)
                            .OrderByDescending(x => x.ProdDbId)
                            .ToList();
                // conversione
                answ = dbRes.Select(x => coreConv(x)).ToList();
            }
            return answ;
        }

        /// <summary>
        /// Restitusice conteggio di item (dato BtlPartId) nello stato richiesto per il project richeisto...
        /// </summary>
        /// <param name="ProjId">Id progetto</param>
        /// <param name="BtlPartId">Id BTL Part</param>
        /// <param name="StateReq">Stato richeisto (enum Core)</param>
        /// <returns></returns>
        public int getCountItemState(int ProjId, int BtlPartId, Core.ItemState StateReq)
        {
            int numItem = 0;
            using (DatabaseContext localDbCtx = new DatabaseContext(DbConfig.CONNECTION_STRING))
            {
                numItem = localDbCtx
                    .PartList
                    .Where(x => x.BTLPart.PartId == BtlPartId && x.BTLPart.Project.ProjId == ProjId && x.State == StateReq)
                    .Count();
            }
            return numItem;
        }

        /// <summary>
        /// Elenco progetti
        /// </summary>
        /// <param name="dtStart">Inizio periodo estrazione (per export date)</param>
        /// <param name="dtEnd">Fine periodo estrazione (per export date)</param>
        /// <param name="numRecord">Num max record da recuperare</param>
        /// <param name="OnlyActive">Solo i record attivi (senza cancellazione logica)</param>
        /// <param name="ShowArchived">Se true: mostra anche archiviati (default li nasconde)</param>
        /// <returns></returns>
        public List<Core.ProjFileM> GetLastByExpDesc(DateTime dtStart, DateTime dtEnd, int numRecord, bool OnlyActive, bool ShowArchived = false)
        {
            List<Core.ProjFileM> answ = new List<Core.ProjFileM>();

            using (DatabaseContext localDbCtx = new DatabaseContext(DbConfig.CONNECTION_STRING))
            {
                // se numRecord = 0 --> passo tutti
                if (numRecord == 0)
                {
                    numRecord = localDbCtx.ProjList.Count();
                }
                // retrieve
                var dbRes = localDbCtx
                                .ProjList
                                .Where(x => (!x.IsArchived || ShowArchived) && (x.DtExported >= dtStart && x.DtExported <= dtEnd) && (!OnlyActive || x.IsActive))
                                .OrderByDescending(x => x.ProjId)
                                .Take(numRecord)
                                .ToList();
                // conversione
                answ = dbRes.Select(x => coreConv(x)).ToList();
            }
            return answ;
        }

        /// <summary>
        /// Elenco progetti
        /// </summary>
        /// <param name="numRecord">Num max record da recuperare</param>
        /// <param name="OnlyActive">Solo i record attivi (senza cancellazione logica)</param>
        /// <param name="ShowArchived">Se true: mostra anche archiviati (default li nasconde)</param>
        /// <returns></returns>
        public List<Core.ProjFileM> GetLastDesc(int numRecord, bool OnlyActive, bool ShowArchived = false)
        {
            List<Core.ProjFileM> answ = new List<Core.ProjFileM>();

            using (DatabaseContext localDbCtx = new DatabaseContext(DbConfig.CONNECTION_STRING))
            {
                // se numRecord = 0 --> passo tutti
                if (numRecord == 0)
                {
                    numRecord = localDbCtx.ProjList.Count();
                }
                // retrieve
                var dbRes = localDbCtx
                                .ProjList
                                .Where(x => (!x.IsArchived || ShowArchived) && (!OnlyActive || x.IsActive))
                                .OrderByDescending(x => x.ProjId)
                                .Take(numRecord)
                                .ToList();
                // conversione
                answ = dbRes.Select(x => coreConv(x)).ToList();
            }
            return answ;
        }

        /// <summary>
        /// Elenco progetti
        /// </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 i record attivi (senza cancellazione logica)</param>
        /// <param name="ShowArchived">Se true: mostra anche archiviati (default li nasconde)</param>
        /// <returns></returns>
        public List<Core.ProjFileM> GetLastDesc(DateTime dtStart, DateTime dtEnd, int numRecord, bool OnlyActive, bool ShowArchived = false)
        {
            List<Core.ProjFileM> answ = new List<Core.ProjFileM>();

            using (DatabaseContext localDbCtx = new DatabaseContext(DbConfig.CONNECTION_STRING))
            {
                // se numRecord = 0 --> passo tutti
                if (numRecord == 0)
                {
                    numRecord = localDbCtx.ProjList.Count();
                }
                // retrieve
                var dbRes = localDbCtx
                                .ProjList
                                .Where(x => (!x.IsArchived || ShowArchived) && (x.DtCreated >= dtStart && x.DtCreated <= dtEnd) && (!OnlyActive || x.IsActive))
                                .OrderByDescending(x => x.ProjId)
                                .Take(numRecord)
                                .ToList();
                // conversione
                answ = dbRes.Select(x => coreConv(x)).ToList();
            }
            return answ;
        }

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

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

                // creo nuovo...
                var newRec = localDbCtx
                    .ProjList
                    .Add(new ProjModel()
                    {
                        ProjId = nextId,
                        BTLFileName = "",
                        ProjDescription = "",
                        IsNew = true,
                        Locked = true,
                        LockedBy = UserKey,
                        LockDate = DateTime.Now,
                        DtCreated = DateTime.Now
                    });

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

        /// <summary> Manage Lock by ProjId (proj & prod) </summary> <param name="ProjId">ID
        /// Proj</param> <param name="Locked">Stato Lock da impostare</param> <param
        /// name="UserKey">User ID / Key number</param> <returns></returns>
        public Core.ProjFileM LockByProjId(int ProjId, bool Locked, string UserKey = "USER01")
        {
            ProjModel currProj;
            using (DatabaseContext localDbCtx = new DatabaseContext(DbConfig.CONNECTION_STRING))
            {
                currProj = localDbCtx
                            .ProjList
                            .Where(x => x.ProjId == ProjId)
                            .SingleOrDefault();
                // aggiorno stato del proj
                currProj.Locked = Locked;
                currProj.LockDate = DateTime.Now;
                currProj.LockedBy = Locked ? UserKey : "";
                localDbCtx.Entry(currProj).State = System.Data.Entity.EntityState.Modified;

                // seleziono il prod e lo blocco...
                var currProd = localDbCtx
                                .ProdList
                                .Where(x => x.ProdDbId == currProj.ProdDbId)
                                .SingleOrDefault();

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

                    // ora blocco altri proj del prod...
                    var currProjs = localDbCtx
                                       .ProjList
                                       .Where(x => x.ProdDbId == currProd.ProdDbId && x.ProjId != ProjId)
                                       .ToList();

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

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

        /// <summary>
        /// Reimposta come NEW
        /// </summary>
        /// <param name="ProjId">ProjID</param>
        /// <param name="Locked">Stato Lock da impostare</param>
        /// <returns></returns>
        public Core.ProjFileM ResetNew(int ProjId)
        {
            ProjModel currProj;
            using (DatabaseContext localDbCtx = new DatabaseContext(DbConfig.CONNECTION_STRING))
            {
                currProj = localDbCtx
                            .ProjList
                            .Where(x => x.ProjId == ProjId)
                            .SingleOrDefault();

                // aggiorno stato
                currProj.IsNew = false;
                localDbCtx.SaveChanges();
            }
            return coreConv(currProj);
        }

        /// <summary>
        /// Update single PROJ
        /// </summary>
        /// <param name="updItem"></param>
        /// <returns></returns>
        public bool Update(ProjModel updItem)
        {
            bool done = false;
            using (DatabaseContext localDbCtx = new DatabaseContext(DbConfig.CONNECTION_STRING))
            {
                var item2update = localDbCtx
                                    .ProjList
                                    .Where(x => x.ProjId == updItem.ProjId)
                                    .SingleOrDefault();
                if (item2update != null)
                {
                    try
                    {
                        updItem.ProjDbId = item2update.ProjDbId;
                        // update, vers 1...
                        localDbCtx.Entry(item2update).CurrentValues.SetValues(updItem);

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

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

        /// <summary>
        /// Update record su DB x elenco BTLParts
        /// </summary>
        /// <param name="ProjId"></param>
        /// <param name="newBTLFileName"></param>
        /// <returns></returns>
        public ProjModel UpdateBtlParts(int ProjId, List<Core.BTLPartM> BtlPartList)
        {
            // record del proj corrente
            var currData = FindByProjId(ProjId);

            using (DatabaseContext localDbCtx = new DatabaseContext(DbConfig.CONNECTION_STRING))
            {
                // 2021.05.03 modifica update: esistenti le MODIFICO, nuove aggiungo, inesistenti
                // elimino in cascata con Part

                // sel delle BTLParts del proj
                List<BTLPartModel> oldBtlParts = localDbCtx
                                                    .BTLPartList
                                                    .Where(x => x.ProjDbId == currData.ProjDbId)
                                                    .ToList();
                if (oldBtlParts != null)
                {
                    var locBtlCtrl = new BTLPartController();
                    // converto le BtlParts da core --> DB
                    List<BTLPartModel> newBtlParts = BtlPartList.Select(x => locBtlCtrl.ConvertFromCore(x, currData.ProjDbId)).ToList();

                    try
                    {
                        // elementi BtlPartId NON + presenti da eliminare
                        List<int> bpi2rem = oldBtlParts.Select(x => x.PartId).Except(newBtlParts.Select(y => y.PartId)).ToList();
                        List<int> bpi2add = newBtlParts.Select(x => x.PartId).Except(oldBtlParts.Select(y => y.PartId)).ToList();
                        List<int> bpiExis = newBtlParts.Select(x => x.PartId).Intersect(oldBtlParts.Select(y => y.PartId)).ToList();

                        // aggiorno existing...
                        foreach (var currPartId in bpiExis)
                        {
                            // recupero item da aggiornare...
                            var oldItem = oldBtlParts.Where(x => x.PartId == currPartId).FirstOrDefault();
                            // dati nuovo item
                            var newItem = newBtlParts.Where(x => x.PartId == currPartId).FirstOrDefault();
                            if (newItem != null && oldItem != null)
                            {
                                oldItem.CALC_State = newItem.CALC_State;
                                oldItem.CNT = newItem.CNT;
                                oldItem.DO = newItem.DO;
                                oldItem.H = newItem.H;
                                oldItem.L = newItem.L;
                                oldItem.W = newItem.W;
                                oldItem.Material = newItem.Material;
                                oldItem.NAM = newItem.NAM;
                                oldItem.PDN = newItem.PDN;
                            }
                        }

                        // aggiungo le nuove part
                        foreach (var newPartId in bpi2add)
                        {
                            var newItem = newBtlParts.Where(x => x.PartId == newPartId).FirstOrDefault();
                            localDbCtx.BTLPartList.Add(newItem);
                        }

                        // elimino dal DB i non + esistenti
                        foreach (var oldPartId in bpi2rem)
                        {
                            // elimino parts nei MachGroup
                            var oldIstPartList = localDbCtx.PartList.Where(x => x.BTLPart.PartId == oldPartId).ToList();
                            localDbCtx.PartList.RemoveRange(oldIstPartList);
                            // elimino BtlParts
                            var oldItem = oldBtlParts.Where(x => x.PartId == oldPartId).FirstOrDefault();
                            localDbCtx.BTLPartList.Remove(oldItem);
                        }
                    }
                    catch
                    { }

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

                    // Commit changes
                    localDbCtx.SaveChanges();
                }
                else
                {
                    string errMessage = $"ERROR on Proj.UpdateBtlParts: req item was not found | ProjId {ProjId} | BtlPartList {BtlPartList.Count} items";
                    Console.WriteLine(errMessage);
                    Log.Error(errMessage);
                }
            }
            return currData;
        }

        /// <summary>
        /// Update record su DB x Description
        /// </summary>
        /// <param name="ProjId"></param>
        /// <param name="Description"></param>
        /// <returns></returns>
        public Core.ProjFileM UpdateDescription(int ProjId, string Description)
        {
            // cerco specifico Proj
            ProjModel currData;
            using (DatabaseContext localDbCtx = new DatabaseContext(DbConfig.CONNECTION_STRING))
            {
                currData = localDbCtx
                               .ProjList
                               .Where(x => x.ProjId == ProjId)
                               .SingleOrDefault();
                if (currData != null)
                {
                    try
                    {
                        // aggiorno valore BTL
                        currData.ProjDescription = Description;

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

            return coreConv(currData);
        }

        /// <summary>
        /// Update record su DB x nomeBTL, ListName, ExportDate
        /// </summary>
        /// <param name="ProjId"></param>
        /// <param name="BTLFileName"></param>
        /// <param name="Description"></param>
        /// <param name="ListName"></param>
        /// <param name="DtExported"></param>
        /// <param name="PType"></param>
        /// <param name="Machine"></param>
        /// <returns></returns>
        public Core.ProjFileM UpdateInfo(int ProjId, string BTLFileName, string Description, string ListName, DateTime DtExported, BWType PType, string Machine)
        {
            // cerco specifico Proj
            ProjModel currData;
            using (DatabaseContext localDbCtx = new DatabaseContext(DbConfig.CONNECTION_STRING))
            {
                currData = localDbCtx
                               .ProjList
                               .Where(x => x.ProjId == ProjId)
                               .SingleOrDefault();
                if (currData != null)
                {
                    try
                    {
                        // 2022.01.24: verifico UNIVOCITA' nel nome del file: SE fosse duplicato -->
                        // nuovo nome, nel formato nomeOriginale_idx, dove idx è il contatore libero
                        // successivo 2023.06.08: lasciato come prima, anche NON attivi
                        // (cancellazione logica)
                        var duplicateList = FindByBtlFileName(BTLFileName, false);
                        // devo verificare SOLO SE la lista non è vuota
                        if (duplicateList != null && duplicateList.Count > 0)
                        {
                            // se ne ho esattamente 1 nel DB allora DEVE essere il record Parent
                            if (duplicateList.Count == 1)
                            {
                                // verifico se ProjId variato
                                if (!duplicateList[0].ProjId.Equals(currData.ProjId))
                                {
                                    // in questo caso ho il PRIMO duplicato
                                    BTLFileName = $"{BTLFileName}_1";
                                }
                            }
                            // se ne ho + di 1 --> so che il maxId interno avrò il valore ULTIMO x
                            // prendere il successivo
                            else
                            {
                                var lastRec = duplicateList.OrderByDescending(x => x.ProjDbId).FirstOrDefault();
                                // cerco indice
                                string maybeNumber = lastRec.BTLFileName.Replace($"{BTLFileName}_", "");
                                int index = 0;
                                bool isNumber = int.TryParse(maybeNumber, out index);
                                // fasccio comunque verifica sia numerico
                                if (isNumber)
                                {
                                    // in questo caso ho il l'ULTIMO duplicato e faccio +1
                                    BTLFileName = $"{BTLFileName}_{index + 1}";
                                }
                            }
                        }

                        // aggiorno valore BTL
                        currData.BTLFileName = BTLFileName;
                        // aggiorno il resto
                        currData.ProjDescription = Description;
                        currData.DtExported = DtExported;
                        currData.ListName = ListName;
                        currData.PType = PType;
                        currData.Machine = Machine;

                        // Commit changes
                        localDbCtx.SaveChanges();
                    }
                    catch (Exception exc)
                    {
                        string errMessage = $"EXCEPTION on Part.UpdateInfo:{Environment.NewLine}{exc}";
                        Console.WriteLine(errMessage);
                        Log.Error(errMessage);
                    }
                }
                else
                {
                    string errMessage = $"ERROR on Proj.UpdateInfo: req item was not found | ProjId {ProjId} | Description {BTLFileName} | ListName {ListName} | DtExported {DtExported} | PType {PType} | Machine {Machine}";
                    Console.WriteLine(errMessage);
                    Log.Error(errMessage);
                }
            }

            return coreConv(currData);
        }

        /// <summary>
        /// Update record su DB x nomeBTL, ListName, ExportDate
        /// </summary>
        /// <param name="ProjId"></param>
        /// <param name="ListName"></param>
        /// <returns></returns>
        public Core.ProjFileM UpdateListName(int ProjId, string ListName)
        {
            ProjModel currData = new ProjModel();
            using (DatabaseContext localDbCtx = new DatabaseContext(DbConfig.CONNECTION_STRING))
            {
                try
                {
                    currData = localDbCtx
                                   .ProjList
                                   .Where(x => x.ProjId == ProjId)
                                   .SingleOrDefault();
                    if (currData != null)
                    {
                        // aggiorno valore BTL
                        currData.ListName = ListName;

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

        /// <summary>
        /// Update record su DB x PType
        /// </summary>
        /// <param name="ProjId"></param>
        /// <param name="Machine"></param>
        /// <returns></returns>
        public Core.ProjFileM UpdateMachine(int ProjId, String Machine)
        {
            ProjModel currData = new ProjModel();
            using (DatabaseContext localDbCtx = new DatabaseContext(DbConfig.CONNECTION_STRING))
            {
                try
                {
                    currData = localDbCtx
                               .ProjList
                               .Where(x => x.ProjId == ProjId)
                               .SingleOrDefault();

                    if (currData != null)
                    {
                        // aggiorno valore BTL
                        currData.Machine = Machine;

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

        #endregion Public Methods

        #region Protected Methods

        /// <summary>
        /// Helper conversione modelli
        /// </summary>
        /// <param name="currProj"></param>
        /// <returns></returns>
        protected Core.ProjFileM coreConv(ProjModel currProj)
        {
            Core.ProjFileM answ = null;
            if (currProj != null)
            {
                answ = Core.ProjFileM.CreateProjFileM(currProj.ProjId, ProdIdByProdDbId(currProj.ProdDbId), currProj.DtCreated, currProj.DtExported, currProj.ListName, currProj.BTLFileName, currProj.ProjDescription, currProj.IsNew, currProj.Locked, currProj.PType, currProj.Machine, currProj.IsActive, currProj.IsArchived);
            }
            return answ;
        }

        /// <summary>
        /// Get LAST paginated data from DB (DESC ordered)
        /// </summary>
        /// <param name="numRecord"></param>
        /// <returns></returns>
        protected List<ProjModel> GetLastDbModelDesc(int numRecord)
        {
            // se numRecord = 0 --> passo tutti
            using (DatabaseContext localDbCtx = new DatabaseContext(DbConfig.CONNECTION_STRING))
            {
                if (numRecord == 0)
                {
                    numRecord = localDbCtx.ProjList.Count();
                }
                // retrieve
                return localDbCtx
                        .ProjList
                        .OrderByDescending(x => x.ProjId)
                        .Take(numRecord)
                        .ToList();
            }
        }

        /// <summary>
        /// Get ProdId by ProdDbId, 0 se non trovato
        /// </summary>
        /// <param name="ProdDbId"></param>
        /// <returns></returns>
        protected int ProdIdByProdDbId(int? ProdDbId)
        {
            int answ = 0;

            using (DatabaseContext localDbCtx = new DatabaseContext(DbConfig.CONNECTION_STRING))
            {
                if (ProdDbId != null)
                {
                    var prodRecord = localDbCtx
                                        .ProdList
                                        .Where(x => x.ProdDbId == ProdDbId)
                                        .SingleOrDefault();

                    if (prodRecord != null)
                    {
                        answ = prodRecord.ProdId;
                    }
                }
            }
            return answ;
        }

        #endregion Protected Methods

        #region Private Fields

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

        #endregion Private Fields
    }
}