using EgwProxy.Icoel;
using IOB_UT_NEXT;
using IOB_UT_NEXT.Config;
using MapoSDK;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net.NetworkInformation;

namespace IOB_WIN_SQL.IobSql
{
    /// <summary>
    /// Adapter specializzato per ICOEL e le chiamate tramite DB per i dati
    /// - accettazione lotti prodotto (frontiera / entrata ciliegie)
    /// - export (totale per prodotti)
    /// - tracciabilità (confezioni
    /// </summary>

    public class IcoelDb : Iob.GenericNext
    {
        #region Public Constructors

        /// <summary>
        /// Costruttore dell'IOB Icoel DB
        /// </summary>
        /// <param name="caller">Form chiamante</param>
        /// <param name="IOBConf">Configurazione (legacy)</param>
        /// <param name="IobConfFull">Configurazione (v 4.x)</param>
        public IcoelDb(AdapterFormNext caller, IobConfTree IobConfFull) : base(caller, IobConfFull)
        {
            /* --------------------------------------
             * todo's
             * --------------------------------------
             * - init obj comunicazione da conf e nuget
             * - lanciare sync e verifica stato sync
             */

            string SyncStateServer = getOptPar("SyncStateServer");
            string SyncStateDb = getOptPar("SyncStateDb");
            string SyncStateUser = getOptPar("SyncStateUser");
            string SyncStatePwd = getOptPar("SyncStatePwd");
            string SyncStateCTout = getOptPar("SyncStateCTout");

            string connSyncState = $"data source={SyncStateServer};initial catalog={SyncStateDb};persist security info=True;user id={SyncStateUser};password={SyncStatePwd};MultipleActiveResultSets=True;App=IOB-WIN-NEXT";

            // gestione command timeout da https://erikej.github.io/sqlclient/2020/10/26/sqlclient-commandtimeout-preview.html
            if (!string.IsNullOrEmpty(SyncStateCTout))
            {
                connSyncState = $"{connSyncState};Command Timeout={SyncStateCTout}";
            }

            // eccezione: NON TROVA EntityFramework 6.0.0 o successivo... why?!?
            dbProxy = new DbProxy(connSyncState);

            lastPING = DateTime.Now.AddHours(-1);
        }

        #endregion Public Constructors

        #region Public Methods

        /// <summary>
        /// Implementazione custom esecuzione task specifici
        /// </summary>
        /// <param name="task2exe"></param>
        /// <returns></returns>
        public override Dictionary<string, string> executeTasks(Dictionary<string, string> task2exe, string codTav)
        {
            // unico task ammissibile: fare un SYNC forzato...
            Dictionary<string, string> taskDone = new Dictionary<string, string>();
            if (task2exe != null)
            {
                // controllo se memMap != null...
                if (memMap != null)
                {
                    bool taskOk = false;
                    string taskVal = "";
                    // cerco task specifici: se ho startSetup --> imposto bit DBB701.DBB0.4
                    foreach (var item in task2exe)
                    {
                        taskOk = false;
                        taskVal = "";
                        // converto richiesta in enum...
                        taskType tName = taskType.nihil;
                        Enum.TryParse(item.Key, out tName);
                        // controllo sulla KEY...
                        switch (tName)
                        {
                            case taskType.syncDbData:
                                lgInfo($"executeTasks --> syncDbData");
                                // effettua sync
                                refreshElencoStati();

                                break;

                            default:
                                taskVal = $"IobIcoelDb | taskReq: {tName} | key: {item.Key} | val: {item.Value} | SKIPPED | NO EXEC";
                                lgInfo($"IobIcoelDb | chiamata senza processing: taskOk: {taskOk} | taskVal: {taskVal}");
                                break;
                        }
                    }
                }
            }
            lastReadPLC = DateTime.Now;
            return taskDone;
        }

        /// <summary>
        /// Recupero dati dinamici...
        /// </summary>
        public override Dictionary<string, string> getDynData()
        {
            // valore non presente in vers default... se gestito fare override
            Dictionary<string, string> outVal = new Dictionary<string, string>();
            // recupero da DB locale stato sync attuale
            var elencoSyncStateCurr = dbProxy.DataController.SyncStateGetAll();
            foreach (var item in elencoSyncStateCurr)
            {
                saveValue(ref outVal, $"{item.TableName}_NumRec", item.NumRec);
                saveValue(ref outVal, $"{item.TableName}_NumRecIn", item.NumRecIn);
                saveValue(ref outVal, $"{item.TableName}_LastIdx", item.LastIdx);
                saveValue(ref outVal, $"{item.TableName}_LastIdxIn", item.LastIdxIn);
            }

            // aggiungo anche i campi currData
            var currData = dbProxy.DataController.CurrDataGetAll();
            foreach (var item in currData)
            {
                saveValue(ref outVal, item.Topic, (double)item.CurrVal);
            }

            lastReadPLC = DateTime.Now;
            return outVal;
        }

        /// <summary>
        /// Effettua processing CUSTOM x Icoel:
        /// - recupera elenco batch delle 2 linee
        /// - invia al sistema
        /// </summary>
        public override void processCustomTaskLF()
        {
            lgInfo($"Richiesto processCustomTaskLF");
            // effettua sync
            refreshElencoStati();
            lastReadPLC = DateTime.Now;
        }

        /// <summary>
        /// Effettua lettura semafori principale <paramref name="currDispData">Parametri da
        /// aggiornare x display in form</paramref>
        /// </summary>
        public override void readSemafori(ref newDisplayData currDispData)
        {
            if (connectionOk)
            {
                B_input = 1;
                currDispData.semIn = Semaforo.SV;

                if (dbProxy != null && elencoSyncState != null && elencoSyncState.Count > 0)
                {
                    B_input += (1 << 1);
                }

                // accodo NON emergenza
                B_input += (1 << 7);
            }
            else
            {
                B_input = 0;
                currDispData.semIn = Semaforo.SR;
            }
        }

        /// <summary>
        /// Override connessione
        /// </summary>
        public override void tryConnect()
        {
            if (!connectionOk)
            {
                // controllo che il ping sia stato tentato almeno pingTestSec fa...
                if (DateTime.Now.Subtract(lastPING).TotalSeconds > utils.CRI("pingTestSec"))
                {
                    if (verboseLog || periodicLog)
                    {
                        lgInfo("IcoelSoap: ConnKO - tryConnect");
                    }
                    // in primis salvo data ping...
                    lastPING = DateTime.Now;
                    // se passa il ping faccio il resto...
                    if (testPingMachine == IPStatus.Success)
                    {
                        string szStatusConnection = "";
                        try
                        {
                            // ora provo connessione...
                            parentForm.commPlcActive = true;
                            if (dbProxy != null)
                            {
                                elencoSyncState = dbProxy.DataController.SyncStateDoImportAll();

                                if (elencoSyncState != null && elencoSyncState.Count > 0)
                                {
                                    parentForm.commPlcActive = false;
                                    connectionOk = true;
                                }
                            }
                            // refresh stato connessione!!!
                            if (connectionOk)
                            {
                                queueInEnabCurr = true;
                                if (adpRunning)
                                {
                                    lgInfo("Connessione OK");
                                    lastReadPLC = DateTime.Now;
                                }
                            }
                            else
                            {
                                lgError("Impossibile procedere, connessione mancante...");
                            }
                        }
                        catch (Exception exc)
                        {
                            lgFatal($"Errore nella connessione all'adapter IcoelSoap: {szStatusConnection}{Environment.NewLine}{exc}");
                            connectionOk = false;
                            lgInfo($"Eccezione in TryConnect, Adapter IcoelSoap NON running, pausa di {utils.CRI("waitRecMSec")} msec prima di ulteriori tentativi di riconnessione");
                        }
                    }
                    else
                    {
                        // loggo no risposta ping ...
                        connectionOk = false;
                        if (verboseLog || periodicLog)
                        {
                            lgInfo($"Attenzione: IcoelSoap controllo PING fallito per IP {IOBConfFull.Device.Connect.PingIpAddr}");
                        }
                    }
                }
            }
            else
            {
                needRefresh = true;
            }
        }

        public override void tryDisconnect()
        {
            // registro solo che è disconnesso
            connectionOk = false;
            queueInEnabCurr = false;
        }

        #endregion Public Methods

        #region Protected Properties

        protected EgwProxy.Icoel.DbProxy dbProxy { get; set; } = null;

        /// <summary>
        /// Stato di sync delle tab gestite
        /// </summary>
        protected List<EgwProxy.Icoel.DataLayer.DatabaseModels.SyncStateModel> elencoSyncState { get; set; } = new List<EgwProxy.Icoel.DataLayer.DatabaseModels.SyncStateModel>();

        #endregion Protected Properties

        #region Private Methods

        private void refreshElencoStati()
        {
            Stopwatch sw = new Stopwatch();
            sw.Start();
            elencoSyncState = dbProxy.DataController.SyncStateDoImportAll();
            sw.Stop();
            lastReadPLC = DateTime.Now;
            lgInfo($"DB: esecuzione task dbProxy.DataController.SyncStateGetAll() in {sw.ElapsedMilliseconds} ms");

            if (elencoSyncState != null)
            {
                foreach (var item in elencoSyncState)
                {
                    lgTrace($"TAB: {item.TableName} | IdxIN / IdxLocal {item.LastIdxIn} / {item.LastIdx} | NumIn / NumLocal {item.NumRecIn} / {item.NumRec}");
                }
            }
        }

        #endregion Private Methods
    }
}