using EgtBEAMWALL.DataLayer.DatabaseModels;
using NLog;
using System;
using System.Linq;

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

        public PartController()
        { }

        #endregion Public Constructors

        #region Public Methods

        /// <summary>
        /// Conversion of base class to DB model class
        /// </summary>
        /// <param name="corePart"></param>
        /// <param name="currMachGroupDbId"></param>
        /// <returns></returns>
        public PartModel ConvertFromCore(Core.PartM corePart, int currMachGroupDbId)
        {
            PartModel answ = new PartModel();
            if (corePart != null)
            {
                int BTLPartId = FindBtlPartByBPI(corePart.nProjId, corePart.nBTLPartId);
                answ = new PartModel()
                {
                    PartId = corePart.nPartId,
                    PDN = corePart.nPDN,
                    BTLPartDbId = BTLPartId,
                    MachGroupDbId = currMachGroupDbId,
                    State = corePart.nProductionState,
                    NAM = corePart.sNAM,
                    W = corePart.dW,
                    L = corePart.dL,
                    H = corePart.dH,
                    Material = corePart.sMATERIAL,
                    DtStart = corePart.dtStartTime,
                    DtEnd = corePart.dtEndTime,
                    //DO = corePart.bDO,
                    //CNT = corePart.nCNT,
                    //TBP = corePart.nTBP,
                    //DON = corePart.nDON,
                    ROT = corePart.nCALC_ROT,
                    //GRP = corePart.sGRP,
                    //UNT = corePart.nUNT,
                    CALC_State = (int)corePart.nCALC_State
                };
            }
            return answ;
        }

        /// <summary>
        /// Delete single Part
        /// </summary>
        /// <param name="ProdId"></param>
        /// <param name="MachGroupId"></param>
        /// <param name="PartId"></param>
        /// <returns></returns>
        public bool Delete(int ProdId, int MachGroupId, int PartId)
        {
            bool done = false;
            using (DatabaseContext localDbCtx = new DatabaseContext(DbConfig.CONNECTION_STRING))
            {
                var myStatusMapCtrl = new StatusMapController();
                var item2del = localDbCtx
                                .PartList
                                .Where(x => x.MachGroup.Prod.ProdId == ProdId && x.MachGroup.MachGroupId == MachGroupId && x.PartId == PartId)
                                .SingleOrDefault();

                if (item2del != null)
                {
                    try
                    {
                        // Remove from database
                        localDbCtx.PartList.Remove(item2del);
                        // Commit changes
                        localDbCtx.SaveChanges();
                        done = true;
                        // aggiorno info sullo status
                        myStatusMapCtrl.UpdateAction("", ProdId, MachGroupId, Core.StatusMapItemType.MachGroup, Core.StatusMapOpType.MachGroupMod, "");
                    }
                    catch (Exception exc)
                    {
                        string errMessage = $"EXCEPTION on Part.Delete: ProdId: {ProdId} | MachGroupId: {MachGroupId} | PartId: {PartId}{Environment.NewLine}{exc}";
                        Console.WriteLine(errMessage);
                        Log.Error(errMessage);
                    }
                }
                else
                {
                    string errMessage = $"ERROR on Part.Delete (01): req item was not found | ProdId {ProdId} | MachGroupId {MachGroupId} | PartId {PartId}";
                    Console.WriteLine(errMessage);
                    Log.Error(errMessage);
                }
            }
            return done;
        }

        /// <summary>
        /// Delete single Part
        /// </summary>
        /// <param name="PartDbId"></param>
        /// <returns></returns>
        public bool Delete(int PartDbId)
        {
            bool done = false;
            using (DatabaseContext localDbCtx = new DatabaseContext(DbConfig.CONNECTION_STRING))
            {
                var item2del = localDbCtx
                                .PartList
                                .Where(x => x.PartDbId == PartDbId)
                                .SingleOrDefault();

                if (item2del != null)
                {
                    try
                    {
                        // Add to database
                        localDbCtx.PartList.Remove(item2del);
                        // Commit changes
                        localDbCtx.SaveChanges();
                        done = true;
                    }
                    catch (Exception exc)
                    {
                        string errMessage = $"EXCEPTION on Part.Delete: {Environment.NewLine}{exc}";
                        Console.WriteLine(errMessage);
                        Log.Error(errMessage);
                    }
                }
                else
                {
                    string errMessage = $"ERROR on Part.Delete (02): req item was not found | PartDbId {PartDbId}";
                    Console.WriteLine(errMessage);
                    Log.Error(errMessage);
                }
            }
            return done;
        }

        /// <summary>
        /// Delete Part by project
        /// </summary>
        /// <param name="MachGroupDbId"></param>
        /// <returns></returns>
        public bool DeleteByMachGroup(int MachGroupDbId)
        {
            bool done = false;
            using (DatabaseContext localDbCtx = new DatabaseContext(DbConfig.CONNECTION_STRING))
            {
                var items2del = localDbCtx
                                .PartList
                                .Where(x => x.MachGroupDbId == MachGroupDbId);
                try
                {
                    // Add to database
                    localDbCtx.PartList.RemoveRange(items2del);
                    // Commit changes
                    localDbCtx.SaveChanges();
                    done = true;
                }
                catch (Exception exc)
                {
                    string errMessage = $"EXCEPTION on Part.DeleteByMachGroup: {Environment.NewLine}{exc}";
                    Console.WriteLine(errMessage);
                    Log.Error(errMessage);
                }
            }
            return done;
        }

        public void Dispose()
        {
        }

        /// <summary>
        /// Get record by DBId
        /// </summary>
        /// <param name="PartDbId"></param>
        /// <returns></returns>
        public PartModel FindByDbId(int PartDbId)
        {
            using (DatabaseContext localDbCtx = new DatabaseContext(DbConfig.CONNECTION_STRING))
            {
                return localDbCtx
                        .PartList
                        .Where(x => x.PartDbId == PartDbId)
                        .SingleOrDefault();
            }
        }

        /// <summary>
        /// Get record by ExtId
        /// </summary>
        /// <param name="PartId"></param>
        /// <returns></returns>
        public PartModel FindByPartId(int ProdId, int PartId)
        {
            PartModel answ = null;
            using (DatabaseContext locallocalDbCtx = new DatabaseContext(DbConfig.CONNECTION_STRING))
            {
                answ = locallocalDbCtx
                        .PartList
                        .Where(x => x.MachGroup.Prod.ProdId == ProdId && x.PartId == PartId)
                        .FirstOrDefault();
            }
            return answ;
        }

        /// <summary>
        /// Update single Part
        /// </summary>
        /// <param name="updItem"></param>
        /// <returns></returns>
        public bool Update(PartModel updItem)
        {
            bool done = false;
            using (DatabaseContext locallocalDbCtx = new DatabaseContext(DbConfig.CONNECTION_STRING))
            {
                var myStatusMapCtrl = new StatusMapController();
                var item2upd = locallocalDbCtx
                                    .PartList
                                    .Where(x => x.PartDbId == updItem.PartDbId)
                                    .SingleOrDefault();
                if (item2upd != null)
                {
                    try
                    {
                        // update, vers 1...
                        locallocalDbCtx.Entry(item2upd).CurrentValues.SetValues(updItem);

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

                        // Commit changes
                        locallocalDbCtx.SaveChanges();
                        done = true;
                        // aggiorno info sullo status
                        myStatusMapCtrl.UpdateAction("", updItem.MachGroup.Prod.ProdId, updItem.PartId, Core.StatusMapItemType.Part, Core.StatusMapOpType.MachGroupMod, "");
                    }
                    catch (Exception exc)
                    {
                        string errMessage = $"EXCEPTION on Part.Update: {Environment.NewLine}{exc}";
                        Console.WriteLine(errMessage);
                        Log.Error(errMessage);
                    }
                }
                else
                {
                    string errMessage = $"ERROR on Part.Update (01): req item was not found | PartId {updItem.PartId} | PartDbId {updItem.PartDbId} | BTLPartDbId {updItem.BTLPartDbId}";
                    Console.WriteLine(errMessage);
                    Log.Error(errMessage);
                }
            }
            return done;
        }

        /// <summary>
        /// Set EndDate for Part
        /// </summary>
        /// <param name="PartId"></param>
        /// <param name="DtEnd"></param>
        /// <returns></returns>
        public bool UpdateEnd(int ProdId, int MachGroupId, int PartId, DateTime DtEnd)
        {
            bool done = false;
            using (DatabaseContext locallocalDbCtx = new DatabaseContext(DbConfig.CONNECTION_STRING))
            {
                var myStatusMapCtrl = new StatusMapController();
                try
                {
                    // aggiorno
                    var item2upd = locallocalDbCtx
                        .PartList
                        .Where(x => x.MachGroup.Prod.ProdId == ProdId && x.MachGroup.MachGroupId == MachGroupId && x.PartId == PartId)
                        .FirstOrDefault();

                    if (item2upd != null)
                    {
                        item2upd.DtEnd = DtEnd;
                        // Commit changes
                        locallocalDbCtx.SaveChanges();
                        done = true;
                        // aggiorno info sullo status
                        myStatusMapCtrl.UpdateAction("", ProdId, PartId, Core.StatusMapItemType.Part, DtEnd == DateTime.MinValue ? Core.StatusMapOpType.ResetPartEnd : Core.StatusMapOpType.PartEnd, "");
                    }
                    else
                    {
                        string errMessage = $"ERROR on Part.UpdateEnd: req item was not found | ProdId {ProdId} | MachGroupId {MachGroupId} | PartId {PartId} | DtEnd {DtEnd}";
                        Console.WriteLine(errMessage);
                        Log.Error(errMessage);
                    }
                }
                catch (Exception exc)
                {
                    string errMessage = $"EXCEPTION on Part.UpdateEnd: {Environment.NewLine}{exc}";
                    Console.WriteLine(errMessage);
                    Log.Error(errMessage);
                }
            }
            return done;
        }

        /// <summary>
        /// Set StartDate for Part
        /// </summary>
        /// <param name="PartId"></param>
        /// <param name="DtStart"></param>
        /// <returns></returns>
        public bool UpdateStart(int ProdId, int MachGroupId, int PartId, DateTime DtStart)
        {
            bool done = false;
            using (DatabaseContext locallocalDbCtx = new DatabaseContext(DbConfig.CONNECTION_STRING))
            {
                var myStatusMapCtrl = new StatusMapController();
                try
                {
                    // aggiorno
                    var item2upd = locallocalDbCtx
                        .PartList
                        .Where(x => x.MachGroup.Prod.ProdId == ProdId && x.MachGroup.MachGroupId == MachGroupId && x.PartId == PartId)
                        .FirstOrDefault();
                    if (item2upd != null)
                    {
                        item2upd.DtStart = DtStart;
                        // Commit changes
                        locallocalDbCtx.SaveChanges();
                        done = true;
                        // aggiorno info sullo status
                        myStatusMapCtrl.UpdateAction("", ProdId, PartId, Core.StatusMapItemType.Part, DtStart == DateTime.MinValue ? Core.StatusMapOpType.ResetPartStart : Core.StatusMapOpType.PartStart, "");
                    }
                    else
                    {
                        string errMessage = $"ERROR on Part.UpdateStart: req item was not found | ProdId {ProdId} | MachGroupId {MachGroupId} | PartId {PartId} | DtStart {DtStart}";
                        Console.WriteLine(errMessage);
                        Log.Error(errMessage);
                    }
                }
                catch (Exception exc)
                {
                    string errMessage = $"EXCEPTION on Part.UpdateStart: {Environment.NewLine}{exc}";
                    Console.WriteLine(errMessage);
                    Log.Error(errMessage);
                }
            }

            return done;
        }

        /// <summary>
        /// Set Status for Part
        /// </summary>
        /// <param name="PartId"></param>
        /// <param name="newState"></param>
        /// <returns></returns>
        public bool UpdateStatus(int ProdId, int MachGroupId, int PartId, Core.ItemState newState)
        {
            bool done = false;
            using (DatabaseContext locallocalDbCtx = new DatabaseContext(DbConfig.CONNECTION_STRING))
            {
                var myStatusMapCtrl = new StatusMapController();
                try
                {
                    // aggiorno
                    var item2upd = locallocalDbCtx
                        .PartList
                        .Where(x => x.MachGroup.Prod.ProdId == ProdId && x.MachGroup.MachGroupId == MachGroupId && x.PartId == PartId)
                        .FirstOrDefault();
                    if (item2upd != null)
                    {
                        item2upd.State = newState;
                        // Commit changes
                        locallocalDbCtx.SaveChanges();
                        done = true;
                        // aggiorno info sullo status
                        myStatusMapCtrl.UpdateAction("", ProdId, PartId, Core.StatusMapItemType.Part, newState == Core.ItemState.Scrapped ? Core.StatusMapOpType.SetPartScrapped : Core.StatusMapOpType.MachGroupMod, "");
                    }
                    else
                    {
                        string errMessage = $"ERROR on Part.UpdateStart: req item was not found | ProdId {ProdId} | MachGroupId {MachGroupId} | PartId {PartId} | newState {newState}";
                        Console.WriteLine(errMessage);
                        Log.Error(errMessage);
                    }
                }
                catch (Exception exc)
                {
                    string errMessage = $"EXCEPTION on Part.UpdateStatus: {Environment.NewLine}{exc}";
                    Console.WriteLine(errMessage);
                    Log.Error(errMessage);
                }
            }

            return done;
        }

        #endregion Public Methods

        #region Protected Methods

        /// <summary>
        /// Get BtlPartDBId by ProjId + PDN
        /// </summary>
        /// <param name="ProjId"></param>
        /// <param name="PDN"></param>
        /// <returns></returns>
        protected int FindBtlPart(int ProjId, int PDN)
        {
            int BtlPartDbId = 0;

            using (DatabaseContext locallocalDbCtx = new DatabaseContext(DbConfig.CONNECTION_STRING))
            {
                var btlPart = locallocalDbCtx
                                .BTLPartList
                                .Where(x => x.Project.ProjId == ProjId && x.PDN == PDN)
                                .SingleOrDefault();

                if (btlPart != null)
                {
                    BtlPartDbId = btlPart.BTLPartDbId;
                }
            }
            return BtlPartDbId;
        }

        /// <summary>
        /// Get BtlPartDBId by ProjId + BtlPartId
        /// </summary>
        /// <param name="ProjId"></param>
        /// <param name="BtlPartId"></param>
        /// <returns></returns>
        protected int FindBtlPartByBPI(int ProjId, int BtlPartId)
        {
            int BtlPartDbId = 0;

            using (DatabaseContext localDbCtx = new DatabaseContext(DbConfig.CONNECTION_STRING))
            {
                var btlPart = localDbCtx
                .BTLPartList
                .Where(x => x.Project.ProjId == ProjId && x.PartId == BtlPartId)
                .SingleOrDefault();

                if (btlPart != null)
                {
                    BtlPartDbId = btlPart.BTLPartDbId;
                }
            }
            return BtlPartDbId;
        }

        #endregion Protected Methods

        #region Private Fields

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

        #endregion Private Fields
    }
}