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

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

        public StatusMapController()
        {
        }

        #endregion Public Constructors

        #region Public Methods

        /// <summary>
        /// Elimina i dati di una sessione (SupervisorId) precedente
        /// </summary>
        /// <param name="Session">Se vuoto --&gt; tutti</param>
        /// <returns></returns>
        public bool DeleteSession(string Session)
        {
            bool done = false;
            DateTime adesso = DateTime.Now;
            List<StatusMapModel> SM2Del = new List<StatusMapModel>();

            using (DatabaseContext localDbCtx = new DatabaseContext(DbConfig.CONNECTION_STRING))
            {
                // svuoto la tab mappa precedente (da rivalutare in futuro)
                if (string.IsNullOrEmpty(Session))
                {
                    SM2Del = localDbCtx
                         .StatusMapList
                         .ToList();
                }
                else
                {
                    SM2Del = localDbCtx
                        .StatusMapList
                        .Where(x => x.Session == Session)
                        .ToList();
                }
                try
                {
                    // Remove to database
                    localDbCtx.StatusMapList.RemoveRange(SM2Del);
                    // Commit changes
                    localDbCtx.SaveChanges();
                    done = true;
                }
                catch (Exception exc)
                {
                    string errMessage = $"EXCEPTION on StatusMap.DeleteSession: {Environment.NewLine}{exc}";
                    Console.WriteLine(errMessage);
                    Log.Error(errMessage);
                }
            }
            return done;
        }

        public void Dispose()
        {
        }

        /// <summary>
        /// Get ALL data for session ordered by index DESC
        /// </summary>
        /// <param name="Session"></param>
        /// <returns></returns>
        public List<StatusMapModel> GetBySession(string Session)
        {
            using (DatabaseContext localDbCtx = new DatabaseContext(DbConfig.CONNECTION_STRING))
            {
                // retrieve
                return localDbCtx
                .StatusMapList
                .Where(x => x.Session == Session)
                .OrderByDescending(x => x.Index)
                .ToList();
            }
        }

        /// <summary>
        /// Get data for session where Index &gt; minIndex ordered by index DESC
        /// </summary>
        /// <param name="Session"></param>
        /// <param name="minIndex"></param>
        /// <returns></returns>
        public List<StatusMapModel> GetFrom(string Session, int minIndex = 0)
        {
            using (DatabaseContext localDbCtx = new DatabaseContext(DbConfig.CONNECTION_STRING))
            {
                // retrieve
                return localDbCtx
                .StatusMapList
                .Where(x => x.Session == Session && x.Index >= minIndex)
                .OrderBy(x => x.Index)
                .ToList();
            }
        }

        /// <summary>
        /// Get PROD (all)
        /// </summary>
        /// <param name="Session"></param>
        /// <returns></returns>
        public List<StatusMapModel> GetProd()
        {
            List<StatusMapModel> answ = new List<StatusMapModel>();
            // Initialize database context
            using (DatabaseContext localDbCtx = new DatabaseContext(DbConfig.CONNECTION_STRING))
            {
                // retrieve
                answ = localDbCtx
                    .StatusMapList
                    .Where(x => x.ItemType == Core.StatusMapItemType.Prod)
                    .OrderByDescending(x => x.Index)
                    .ToList();
            }
            return answ;
        }

        /// <summary>
        /// Get PROD for session
        /// </summary>
        /// <param name="Session"></param>
        /// <returns></returns>
        public List<StatusMapModel> GetProd(string Session)
        {
            List<StatusMapModel> answ = new List<StatusMapModel>();
            // Initialize database context
            using (DatabaseContext localDbCtx = new DatabaseContext(DbConfig.CONNECTION_STRING))
            {
                // retrieve
                answ = localDbCtx
                    .StatusMapList
                    .Where(x => x.Session == Session && x.ItemType == Core.StatusMapItemType.Prod)
                    .OrderByDescending(x => x.Index)
                    .ToList();
            }
            return answ;
        }

        /// <summary>
        /// Indica che si inizia a prendere in carico un PROD dal supervisor
        /// </summary>
        /// <param name="ProdId"></param>
        /// <param name="ProjId"></param>
        /// <returns></returns>
        public bool StartProd(int ProdId, string SupervisorId)
        {
            bool done = false;
            DateTime adesso = DateTime.Now;

            // gestione corretta x multi-supervisors
            done = DeleteSession(SupervisorId);

            // se ho fatto inserisco nuovo
            if (done)
            {
                // reset validità
                done = false;
                // inserisco dato prod
                StatusMapModel prodSMRecord = new StatusMapModel() { Session = SupervisorId, Index = 0, ItemId = ProdId, ItemType = Core.StatusMapItemType.Prod, Operation = Core.StatusMapOpType.Startup, DtEvent = adesso, Val = "" };
                // Initialize database context
                using (DatabaseContext localDbCtx = new DatabaseContext(DbConfig.CONNECTION_STRING))
                {
                    // per prima cosa indico come prodotto il PROD...
                    var currProdData = localDbCtx
                              .ProdList
                              .Where(x => x.ProdId == ProdId)
                              .SingleOrDefault();
                    if (currProdData != null)
                    {
                        try
                        {
                            // aggiorno valore descrizione
                            currProdData.IsProduced = true;
                            // Commit changes
                            localDbCtx.SaveChanges();
                            done = true;
                        }
                        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: true";
                        Console.WriteLine(errMessage);
                        Log.Error(errMessage);
                    }
                    // resetto done
                    done = false;
                    // aggiungo in StatusMap
                    localDbCtx.StatusMapList.Add(prodSMRecord);

                    // recupero MachGroup da PROD
                    var MGList = localDbCtx
                                    .MachGroupList
                                    .Where(x => x.Prod.ProdId == ProdId)
                                    .ToList();

                    var mgSMRecords = MGList.Select(x => new StatusMapModel() { Session = SupervisorId, Index = 0, ItemId = x.MachGroupId, ItemType = Core.StatusMapItemType.MachGroup, Operation = Core.StatusMapOpType.Startup, DtEvent = adesso, Val = "" }).ToList();
                    // aggiungo
                    localDbCtx.StatusMapList.AddRange(mgSMRecords);

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

        /// <summary>
        /// Aggiornamento di un record (e del prod) come da richiesta
        /// </summary>
        /// <param name="Session"></param>
        /// <param name="ProdId"></param>
        /// <param name="ItemId"></param>
        /// <param name="ItemType"></param>
        /// <param name="Operation"></param>
        /// <param name="Value"></param>
        /// <returns></returns>
        public bool UpdateAction(string Session, int ProdId, int ItemId, Core.StatusMapItemType ItemType, Core.StatusMapOpType Operation, string Value)
        {
            bool fatto = false;
            // Recupero il record PROD (che è ultimo indice)
            StatusMapModel prodData = new StatusMapModel();
            // Initialize database context
            using (DatabaseContext localDbCtx = new DatabaseContext(DbConfig.CONNECTION_STRING))
            {
                // se è un prod --> vado x ID
                if (Session == "")
                {
                    prodData = localDbCtx
                        .StatusMapList
                        .Where(x => x.ItemType == Core.StatusMapItemType.Prod && x.ItemId == ProdId)
                        .FirstOrDefault();
                }
                else
                {
                    prodData = localDbCtx
                        .StatusMapList
                        .Where(x => x.ItemType == Core.StatusMapItemType.Prod && x.Session == Session)
                        .FirstOrDefault();
                }
                // se ho trovato
                if (prodData != null)
                {
                    try
                    {
                        // aggiorno indice PROD
                        prodData.Index++;
                        // se session è nulla ma ho un PROD --> calcolo da li la sessione
                        if (string.IsNullOrEmpty(Session))
                        {
                            Session = prodData.Session;
                        }
                        // creo un nuovo record
                        DateTime adesso = DateTime.Now;
                        var newRec = new StatusMapModel() { Session = Session, Index = prodData.Index, ItemId = ItemId, ItemType = ItemType, Operation = Operation, DtEvent = adesso, Val = Value };
                        localDbCtx.StatusMapList.Add(newRec);

                        // Commit changes
                        localDbCtx.SaveChanges();
                        fatto = true;
                    }
                    catch (Exception exc)
                    {
                        string errMessage = $"EXCEPTION on StatusMap.UpdateAction: {Environment.NewLine}{exc}";
                        Console.WriteLine(errMessage);
                        Log.Error(errMessage);
                    }
                }
            }
            return fatto;
        }

        #endregion Public Methods

        #region Private Fields

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

        #endregion Private Fields
    }
}