using IOB_UT_NEXT;
using IOB_UT_NEXT.Config;
using MapoSDK;
using Newtonsoft.Json;
using Opc.Ua;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.NetworkInformation;
using System.Threading.Tasks;
using static IOB_UT_NEXT.CustomObj;
using static System.Windows.Forms.VisualStyles.VisualStyleElement;

namespace IOB_WIN_OPC_UA.IobOpc
{
    public class OpcUaSiemensRama : OpcUaSiemens
    {
        #region Public Constructors

        /// <summary>
        /// Estende l'init della classe base, impiegando il pacchetto Nuget OPC-UA foundation con la
        /// gestione specifica per adapter Siemens integrato OPC-UA (es RAMA RED by Unitech x TFT)
        /// https://github.com/OPCFoundation/UA-.NETStandard
        /// </summary>, IobConfTree IobConfFull
        public OpcUaSiemensRama(AdapterFormNext caller, IobConfTree IobConfFull) : base(caller, IobConfFull)
        {
            lgInfo("Init OpcUa Siemens x RAMA");
            doByteRead = true;

            /*-------------------------------------------
             * Gestione custom
             *
             * Creare array vettori di BIN/bool x decodificare info specifiche
             * configurare CABLATO in oggetti custom RAMA
             * decodifica dataitem custom rama dagli oggetti binari
             *
             * QUANDO FUNZIONA verificare se e come rendere parametrica la gestione oggetti/byte configurabili
             *
             *-------------------------------------------*/
            sendKeyRichiesta = true;
        }

        #endregion Public Constructors

        #region Protected Methods

        /// <summary>
        /// Esegue step a valle dell'auto ODL:
        /// - reset contapezzi
        /// - richiesta setup (uguale al precedente)
        /// </summary>
        protected override void processAutoOdlExtraStep()
        {
            // inizio con reset ricetta caricata
            list2Write = new List<objItem>();
            // aggiungo reset caricamento
            objItem resRecipeData = new objItem()
            {
                uid = "ResetAccepted",
                reqValue = "false",
                name = "ResetAccepted"
            };
            list2Write.Add(resRecipeData);
            // effettua chiamata scrittura verso impianto x il solo reset......
            plcWriteParams(ref list2Write);

            // aspetta 1 sec procede
            Task.Delay(1 * 1000);

            // aggiungo ultimo parametro di resetCounter... come 0/1... boh!
            objItem resetCnt = new objItem()
            {
                uid = "ResetCounter",
                reqValue = "1",
                name = "ResetCounter"
            };
            list2Write.Add(resetCnt);

            // effettua chiamata scrittura verso impianto...
            plcWriteParams(ref list2Write);

            // aspetta 1 sec e indica ricetta richiesta
            Task.Delay(1 * 1000);
            list2Write = new List<objItem>();
            // aggiungo ultimo parametro di newRecipe...
            objItem newRecipeData = new objItem()
            {
                uid = "NewRecipe",
                reqValue = "true",
                name = "NewRecipe"
            };
            list2Write.Add(newRecipeData);
            // effettua chiamata scrittura verso impianto...
            plcWriteParams(ref list2Write);

            // aggiungo 1 altro step di attesa alla lettura pezzi x sicurezza...
            dtVetoReadPzCount = DateTime.Now.AddMinutes(delayMinReadPzCount);
        }

        /// <summary>
        /// Effettua sync dati inviando RICETTA
        /// </summary>
        protected override void ProcessDataSync()
        {
            lgInfo("--------------------------------------------");
            lgInfo($"executeTasks --> syncDbData --> processDataSync");
            lgInfo("--------------------------------------------");
            // effettua sync recuperando dati ed effettuando scrittura su kepware
            var taskGet = iobGetSendDossier();
        }

        #endregion Protected Methods

        #region Private Methods

        /// <summary>
        /// Recupero dati da server x invio dati ricetta a OPC-UA Siemens (RAMA x Tenditalia)
        /// NB: modificato rispetto a TFT: invia PODL correntemente in esecuzione (SE DISPONIBILE) oppure il PRIMO di quelli attivabili...
        /// </summary>
        /// <returns></returns>
        private bool iobGetSendDossier()
        {
            bool answ;

            lgInfo("iobGetSendOdlDP: Inizio scrittura dati a server OPC-UA");
            /*-----------------------------------------
             * STEPS processo:
             * - recupero ARTICOLI (solo quelli dei PODL attivi)
             * - recupero PODL (tutti)
             * - recupero elenco DOSSIER last x macchina (legato ai PODL attivi)
             * - prendo SOLO PODL attivi, e prendo il + vecchio
             * - se trovo dossier x articolo del PODL + vecchio (e dovrebbe...) procedo
             * - uso Dictionary dei memWrite x tradurre l'elenco fluxLog in nuovi valori
             * - preparo il set di valori da scrivere con traduzione
             * - invio scritture
             * - aggiungo info articolo (+ ODL...)
             * - aggiungo i valori BIT di "reset contapezzi " + "nuova ricetta"
             *----------------------------------------- */

            bool okArt = false;
            bool okDoss = false;
            bool okPodl = false;
            List<AnagArticoli> listaArt = new List<AnagArticoli>();
            List<PODLModel> listaPODL = new List<PODLModel>();
            List<DossiersModel> listaDoss = new List<DossiersModel>();
            // recupera dati da server tramite chiamate REST a MP/IO/IOB...
            try
            {
                // PONTE SYNC/ASYNC: Ora sw.Stop() aspetterà la fine reale dell'operazione
                Task.Run(async () =>
                {
                    var rawListArt = await callUrl(urlGetCurrArt, false);
                    var rawListDOSS = await callUrl(urlGetCurrDOSS, false);
                    var rawListPODL = await callUrl(urlGetActPODL, false);
                    if (!string.IsNullOrEmpty(rawListArt))
                    {
                        try
                        {
                            listaArt = JsonConvert.DeserializeObject<List<AnagArticoli>>(rawListArt);
                            okArt = listaArt.Count > 0;
                        }
                        catch (Exception exc)
                        {
                            lgError($"Errore: chiamata elenco ART ha restituito errore{Environment.NewLine}{exc}");
                        }
                    }
                    else
                    {
                        lgError($"Errore: chiamata elenco ART ({urlGetCurrArt}) ha restituito valore vuoto");
                    }
                    if (!string.IsNullOrEmpty(rawListDOSS))
                    {
                        try
                        {
                            listaDoss = JsonConvert.DeserializeObject<List<DossiersModel>>(rawListDOSS);
                            okDoss = listaDoss.Count > 0;
                        }
                        catch (Exception exc)
                        {
                            lgError($"Errore: chiamata elenco DOSSIER ha restituito errore{Environment.NewLine}{exc}");
                        }
                    }
                    else
                    {
                        lgError($"Errore: chiamata elenco DOSSIER ({urlGetCurrDOSS}) ha restituito valore vuoto");
                    }
                    if (!string.IsNullOrEmpty(rawListPODL))
                    {
                        try
                        {
                            listaPODL = JsonConvert.DeserializeObject<List<PODLModel>>(rawListPODL);
                            okPodl = listaPODL.Count > 0;
                        }
                        catch (Exception exc)
                        {
                            lgError($"Errore: chiamata elenco DOSSIER ha restituito errore{Environment.NewLine}{exc}");
                        }
                    }
                    else
                    {
                        lgError($"Errore: chiamata elenco PODL ({urlGetActPODL}) ha restituito valore vuoto");
                    }
                })
                .GetAwaiter()
                .GetResult();
            }
            catch (Exception ex)
            {
                lgError($"Errore in iobGetSendDossier | {Environment.NewLine}{ex.Message}");
            }
            // continuo verifica
            answ = okArt && okPodl && okDoss;
            if (answ)
            {
                // verifico i PODL attivi...
                var listPodlAct = listaPODL.Where(x => x.Attivabile).OrderBy(x => x.InsertDate).ToList();
                if (listPodlAct.Count > 0)
                {
                    string codArt = listPodlAct.FirstOrDefault().CodArticolo;
                    // verifico di avere il dossier e l'articolo x questo PODL
                    var selArt = listaArt.Where(x => x.CodArticolo == codArt).FirstOrDefault();
                    var selDoss = listaDoss.Where(x => x.CodArticolo == codArt).FirstOrDefault();
                    // prendo il primo e recupero...
                    if (selArt != null && selDoss != null)
                    {
                        // recupero il resultset dei valori FluxLog da caricare
                        DossierFluxLogDTO resultSet = JsonConvert.DeserializeObject<DossierFluxLogDTO>(selDoss.Valore);
                        List<FluxLog> listFluxLog = resultSet.ODL;

                        // inizio con reset ricetta caricata
                        list2Write = new List<objItem>();
                        // aggiungo reset caricamento
                        objItem resRecipeData = new objItem()
                        {
                            uid = "ResetAccepted",
                            reqValue = "false",
                            name = "ResetAccepted"
                        };
                        list2Write.Add(resRecipeData);
                        // effettua chiamata scrittura verso impianto x il solo reset......
                        plcWriteParams(ref list2Write);

                        // preparo elenco parametri da inviare...

                        // aspetta 1 sec procede
                        Task.Delay(1 * 1000);
                        list2Write = new List<objItem>();
                        // per ogni valore ricevuto nel dossier --> calcolo parametro da inviare
                        foreach (var item in listFluxLog)
                        {
                            objItem currData = new objItem()
                            {
                                uid = item.CodFlux,
                                reqValue = item.Valore,
                                name = item.CodFlux
                            };
                            // aggiungo!
                            list2Write.Add(currData);
                            lgInfo($"Add param: {currData.uid} | reqVal: {currData.reqValue}");
                        }
                        // aggiungo parametro ARTICOLO...
                        objItem setArt = new objItem()
                        {
                            uid = "setArt",
                            reqValue = getMemMapWriteVal("setArt"),
                            name = "setArt"
                        };
                        list2Write.Add(setArt);
                        // aggiungo parametro COMMESSA...
                        objItem setComm = new objItem()
                        {
                            uid = "setComm",
                            reqValue = getMemMapWriteVal("setComm"),
                            name = "setComm"
                        };
                        list2Write.Add(setComm);
                        // aggiungo ultimo parametro di resetCounter... come 0/1... boh!
                        objItem resetCnt = new objItem()
                        {
                            uid = "ResetCounter",
                            reqValue = "1",
                            name = "ResetCounter"
                        };
                        list2Write.Add(resetCnt);

                        // effettua chiamata scrittura verso impianto...
                        plcWriteParams(ref list2Write);

                        // aspetta 1 sec e indica ricetta richiesta
                        Task.Delay(1 * 1000);
                        list2Write = new List<objItem>();
                        // aggiungo ultimo parametro di newRecipe...
                        objItem newRecipeData = new objItem()
                        {
                            uid = "NewRecipe",
                            reqValue = "true",
                            name = "NewRecipe"
                        };
                        list2Write.Add(newRecipeData);
                        // effettua chiamata scrittura verso impianto...
                        plcWriteParams(ref list2Write);
                    }
                }
            }
            return answ;
        }

        #endregion Private Methods
    }
}