using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using System;
using System.Collections.Generic;
using System.Linq;

namespace NKC_SDK
{
    /// <summary>
    /// Classe che rappresenta stato ordine ricevuto via REDIS da NESTING
    /// </summary>
    public class baseNestAnsw
    {
        #region Public Properties

        /// <summary>
        /// ID univoco invio del TASK
        /// </summary>
        public string EnvNum { get; set; } = "";

        /// <summary>
        /// Elenco errori riscontrati
        /// </summary>
        public List<ErrorRep> ErrorList { get; set; } = null;

        /// <summary>
        /// Tempo STIMATO di taglio calcolato dal Nesting espresso in Secondi
        /// </summary>
        public double EstimatedWorktime { get; set; } = 0;

        /// <summary>
        /// Codice della amcchina x cui si effettua richiesta
        /// </summary>
        [JsonConverter(typeof(StringEnumConverter))]
        public mType MachineType { get; set; } = mType.Multiax;

        /// <summary>
        /// Tipo di ordine richiesto
        /// </summary>
        //[JsonConverter(typeof(StringEnumConverter))]
        public oType OrderType { get; set; } = oType.BatchRequest;

        /// <summary>
        /// Tempo di processing del Nesting espresso in Secondi
        /// </summary>
        public double ProcessingRuntime { get; set; } = 0;

        /// <summary>
        /// Note libere del nesting
        /// </summary>
        public string ProcessNotes { get; set; } = "";

        /// <summary>
        /// Status del processo di nesting
        /// </summary>
        public procStatus ProcessStatus { get; set; } = procStatus.waiting;

        /// <summary>
        /// Tipo di processing richiesto
        /// 1 = stima
        /// 2 = nesting
        /// 3 = stima estesa: elenco ordini con tempo x ogni ordine (ORD.RIGA) + numero part + List<CART>...
        /// </summary>
        public int ProcType { get; set; } = 0;

        #endregion Public Properties
    }

    /// <summary>
    /// Classe che rappresenta la richiesta di processing di NESTING da inserire in REDIS
    /// </summary>
    public class batchRequest
    {
        #region Public Properties

        /// <summary>
        /// ID del processo richiesto (generato in fase di import)
        /// </summary>
        public int BatchId { get; set; }

        /// <summary>
        /// ID univoco dell'invio del TASK
        /// </summary>
        public string EnvNum { get; set; } = "";

        /// <summary>
        /// Codice della macchina x cui si effettua richeista
        /// </summary>
        [JsonConverter(typeof(StringEnumConverter))]
        public mType MachineType { get; set; }

        /// <summary>
        /// tempo massimo permesso x nesting (secondi)
        /// </summary>
        public int MaxTime { get; set; }

        /// <summary>
        /// Elenco ordini richiesti da processare / nestare
        /// </summary>
        public List<Order> OrderList { get; set; }

        /// <summary>
        /// Tipo di ordine richiesto
        /// </summary>
        // riportato a numero
        //[JsonConverter(typeof(StringEnumConverter))]
        public oType OrderType { get; set; }

        /// <summary>
        /// Tipo di processing richiesto
        /// 1 = stima
        /// 2 = nesting
        /// </summary>
        public int ProcType { get; set; }

        #endregion Public Properties
    }

    /// <summary>
    /// Classe che rappresenta la richiesta di AZIONI al NESTING
    /// </summary>
    public class commandRequest
    {
        #region Public Properties

        /// <summary>
        /// Richiesta per il nesting: DoNesting / HaltNesting
        /// </summary>
        public string ActionRequested { get; set; }

        /// <summary>
        /// ID del processo richiesto (generato in fase di import)
        /// </summary>
        public int BatchID { get; set; }

        #endregion Public Properties
    }

    /// <summary>
    /// Valori decodificati
    /// </summary>
    public class decodedData
    {
        #region Public Properties

        /// <summary>
        /// Codice decodificato
        /// </summary>
        public string code { get; set; } = "";

        /// <summary>
        /// Codice decodificato in formato INT
        /// </summary>
        public int codeInt { get; set; } = 0;

        /// <summary>
        /// Tipo codice decodificato
        /// </summary>
        public codeType codeType { get; set; } = codeType.UNK;

        /// <summary>
        /// Descrizione associata
        /// </summary>
        public string description { get; set; } = "";

        /// <summary>
        /// Dato letto RAW
        /// </summary>
        public string rawData { get; set; } = "";

        #endregion Public Properties
    }

    /// <summary>
    /// Oggetto errore da poter rispondere con chiamate x stima/nesting
    /// </summary>
    public class ErrorRep
    {
        #region Public Properties

        /// <summary>
        /// Descrizione estesa (human readable) dell'errore
        /// </summary>
        public string Description { get; set; } = "";

        /// <summary>
        /// DataOra registrazione record
        /// </summary>
        public DateTime DtRif { get; set; } = DateTime.Now;

        /// <summary>
        /// Tipo di errore
        /// </summary>
        public string ErrType { get; set; } = "NA";

        /// <summary>
        /// Chiave di riferimento PARENT per l'errore (es il codice del batch, dell'item)
        /// es: BatchId.OrderId.Row
        /// </summary>
        public string ParentUid { get; set; } = "A.B.C";

        /// <summary>
        /// Chiave univoca per l'errore
        /// es: BatchId.OrderId.Row.PartId...
        /// </summary>
        public string Uid { get; set; } = "A.B.C.D";

        #endregion Public Properties
    }

    /// <summary>
    /// Oggetto KIT
    /// </summary>
    public class Kit
    {
        #region Public Properties

        /// <summary>
        /// Codice KIT da cod ordine ext
        /// </summary>
        public string KitExtCode { get; set; } = "";

        /// <summary>
        /// ID KIT (da DB)
        /// </summary>
        public int KitId { get; set; } = 0;

        /// <summary>
        /// Elenco Items da produrre x KIT
        /// </summary>
        public List<Part> PartList { get; set; }

        #endregion Public Properties
    }

    public class MachineStatData
    {
        #region Public Properties

        /// <summary>
        /// Codice macchina
        /// </summary>
        public string Machine { get; set; } = "WRK000";

        /// <summary>
        /// record registrati dalla macchina
        /// </summary>
        public List<MachineStatRecord> Records { get; set; } = new List<MachineStatRecord>();

        #endregion Public Properties
    }

    public class MachineStatRecord
    {
        #region Public Properties

        /// <summary>
        /// Codice evento/stato
        /// 00 = KeepAlive  --> imposto dataora/drift
        /// </summary>
        public string Code { get; set; } = "";

        /// <summary>
        /// DataOra dell'informazione (clock mittente)
        /// </summary>
        public DateTime DtRecord { get; set; } = DateTime.Now;

        /// <summary>
        /// Valore / carico associato all'invio (opzionale)
        /// </summary>
        public string Payload { get; set; } = "";

        /// <summary>
        /// Codice postazione
        /// </summary>
        public string Station { get; set; } = "";

        #endregion Public Properties
    }

    /// <summary>
    /// Definizione classe x materiali
    /// </summary>
    public class Material
    {
        #region Public Properties

        public DateTime ApprovDate { get; set; } = DateTime.Now;
        public string ApprovUser { get; set; } = "";
        public decimal L_mm { get; set; } = 0;
        public string MatDesc { get; set; } = "";
        public string MatDtmx { get; set; } = "";
        public int MatExtCode { get; set; } = 0;
        public int MatId { get; set; } = 0;
        public decimal T_mm { get; set; } = 0;
        public decimal W_mm { get; set; } = 0;

        #endregion Public Properties
    }

    /// <summary>
    /// dati del materiale
    /// </summary>
    public class MaterialData
    {
        #region Public Properties

        /// <summary>
        /// Codice P/N del materiale (cliente)
        /// </summary>
        public string MaterialDescription { get; set; }

        /// <summary>
        /// Identificativo univoco del materiale (DA ANAGRAFICA db)
        /// </summary>
        public int MaterialId { get; set; }

        /// <summary>
        /// Codice P/N del materiale (cliente)
        /// </summary>
        public string MaterialPN { get; set; }

        #endregion Public Properties
    }

    /// <summary>
    /// Dati di un Cart post nesting
    /// </summary>
    public class NestBin
    {
        #region Public Properties

        /// <summary>
        /// Indice del BIN nel TAKT / giorno
        /// </summary>
        public int BinIndex { get; set; } = 0;

        /// <summary>
        /// Elenco dei PART/ITEM dell'Ordine
        /// </summary>
        public List<Part> PartList { get; set; }

        #endregion Public Properties
    }

    /// <summary>
    /// Struttura stack
    /// </summary>
    public class NestBunk
    {
        #region Public Properties

        /// <summary>
        /// Identificativo univoco stack
        /// </summary>
        public String BunkId { get; set; } = "";

        /// <summary>
        /// Indice del Bunk
        /// </summary>
        public int BunkIndex { get; set; } = 0;

        /// <summary>
        /// Num di fogli nello stack
        /// </summary>
        public int NumSheet
        {
            get
            {
                int answ = 0;
                if (SheetList != null)
                {
                    answ = SheetList.Count;
                }
                return answ;
            }
        }

        /// <summary>
        /// Elenco Sheet previsti
        /// </summary>
        public List<NestSheet> SheetList { get; set; }

        #endregion Public Properties
    }

    /// <summary>
    /// Dati di un Cart post nesting
    /// </summary>
    public class NestCart
    {
        #region Public Properties

        /// <summary>
        /// Indice del CART nel TAKC / giorno
        /// </summary>
        public int CartIndex { get; set; } = 0;

        /// <summary>
        /// Elenco dei KIT dell'ordine
        /// </summary>
        public List<Kit> KitList { get; set; }

        /// <summary>
        /// Tempo previsto per produrre il Cart
        /// </summary>
        public double ProcTime { get; set; } = 0;

        #endregion Public Properties
    }

    /// <summary>
    /// Dati di un foglio di Remnant
    /// </summary>
    public class NestRemn
    {
        #region Public Properties

        /// <summary>
        /// Dimensione L del remnant
        /// </summary>
        public decimal L_mm { get; set; } = 0;

        /// <summary>
        /// Dimensione W del remnant
        /// </summary>
        public decimal W_mm { get; set; } = 0;

        #endregion Public Properties
    }

    /// <summary>
    /// Risposta NESTING x la STIMA iniziale ESTESA (chiede dati a livello di ORDERS aggregati)
    /// </summary>
    public class nestReplyBatchExtEst : nestReplyBatchInitial
    {
        #region Public Properties

        /// <summary>
        /// Elenco ordini con dati processing
        /// </summary>
        public List<OrderPrev> EstOrderList { get; set; }

        #endregion Public Properties
    }

    /// <summary>
    /// Risposta NESTING x la STIMA iniziale
    /// </summary>
    public class nestReplyBatchFinal : orderStatus
    {
        #region Public Properties

        /// <summary>
        /// Elenco Bin
        /// </summary>
        public List<NestBin> BinList { get; set; } = new List<NestBin>();

        /// <summary>
        /// Elenco Stack previsti
        /// </summary>
        public List<NestBunk> BunkList { get; set; } = new List<NestBunk>();

        /// <summary>
        /// Elenco Carts
        /// </summary>
        public List<NestCart> CartList { get; set; } = new List<NestCart>();

        #endregion Public Properties
    }

    /// <summary>
    /// Risposta NESTING x la STIMA iniziale
    /// </summary>
    public class nestReplyBatchInitial : orderStatus
    {
        #region Public Properties

        /// <summary>
        /// Elenco Items da produrre x ordine
        /// </summary>
        public List<Part> PartList { get; set; }

        #endregion Public Properties
    }

    public class nestReplyOffOrd : orderStatus
    {
        #region Public Properties

        /// <summary>
        /// Path x folder dei vari CNC dell'offline order
        /// </summary>
        public string CncPath { get; set; } = "";

        /// <summary>
        /// Path x folder dei vari SVG offline order da mostrare
        /// </summary>
        public string DrawingPath { get; set; } = "";

        #endregion Public Properties
    }

    /// <summary>
    /// Classe Sheet x Nesting
    /// </summary>
    public class NestSheet
    {
        #region Public Properties

        /// <summary>
        /// SVG del lavoro previsto
        /// </summary>
        public string Drawing { get; set; } = "";

        /// <summary>
        /// Tempo STIMATO di taglio calcolato dal Nesting espresso in Secondi
        /// </summary>
        public double EstimatedWorktime { get; set; } = 0;

        /// <summary>
        /// Programma x Machining
        /// </summary>
        public string MachiningProgram { get; set; } = "";

        /// <summary>
        /// Materiale
        /// </summary>
        public int MatId { get; set; }

        /// <summary>
        /// Elenco Part da produrre x ordine
        /// </summary>
        public List<Part> PartList { get; set; } = null;

        /// <summary>
        /// Programma x printing
        /// </summary>
        public string PrintProgram { get; set; } = "";

        /// <summary>
        /// Eventuale remnant
        /// </summary>
        public NestRemn Remnant { get; set; }

        /// <summary>
        /// Identificativo univoco Sheet
        /// </summary>
        public String SheetId { get; set; } = "";

        /// <summary>
        /// Indice dello sheet
        /// </summary>
        public int SheetIndex { get; set; } = 0;

        /// <summary>
        /// Resa (OEE) dell'impiego del materiale
        /// </summary>
        public double SurfaceOEE
        {
            get
            {
                double answ = 0;
                try
                {
                    answ = SurfaceWork / SurfaceTotal;
                }
                catch
                { }
                return answ;
            }
        }

        /// <summary>
        /// Superficie totale del foglio lavorato (= materiale)
        /// </summary>
        public double SurfaceTotal { get; set; } = 1;

        /// <summary>
        /// Superficie WORK (lavorata/tagliata) del foglio lavorato (= somma area dei pezzi disposti)
        /// </summary>
        public double SurfaceWork { get; set; } = 0;

        #endregion Public Properties
    }

    /// <summary>
    /// Struttura Ordine passata a NESTING
    /// </summary>
    public class Order
    {
        #region Public Properties

        /// <summary>
        /// Plant di destinazione
        /// </summary>
        public string DestPlant { get; set; }

        /// <summary>
        /// Elenco dei KIT dell'ordine
        /// </summary>
        public List<Kit> KitList { get; set; }

        /// <summary>
        /// Cod ordine di NKC
        /// </summary>
        public string OrderCod { get; set; }

        /// <summary>
        /// Codice ordine esterno da cliente (HFA)
        /// </summary>
        public string OrderExtCode { get; set; }

        /// <summary>
        /// ID Ordine (da DB)
        /// </summary>
        public int OrderId { get; set; } = 0;

        #endregion Public Properties
    }

    /// <summary>
    /// Informazioni ordine tornate da Nesting (previsione)
    /// </summary>
    public class OrderPrev : Order
    {
        #region Public Properties

        /// <summary>
        /// Num totale BIN predisposti
        /// </summary>
        public int NumBin { get; set; } = 0;

        /// <summary>
        /// Num totale CART predisposti
        /// </summary>
        public int NumCart { get; set; } = 0;

        /// <summary>
        /// Num part previste per ordine
        /// </summary>
        public int NumPart { get; set; } = 0;

        /// <summary>
        /// Tempo totale in %
        /// </summary>
        public double Quota { get; set; } = 0;

        /// <summary>
        /// Tempo totale in minuti
        /// </summary>
        public double TotTime { get; set; } = 0;

        #endregion Public Properties
    }

    /// <summary>
    /// Classe simulazione di un assegnazione di un set di ordini (compreso score)
    /// </summary>
    public class OrderSetSim
    {
        #region Public Properties

        /// <summary>
        /// Valore attuale (somma dei punteggi degli elementi)
        /// </summary>
        public double ActualValue
        {
            get
            {
                return OrderSet.Sum(x => x.Value);
            }
        }

        /// <summary>
        /// Valore score (scostamento target/actual)
        /// </summary>
        public double IndexScore
        {
            get
            {
                return Math.Abs(TargetValue - ActualValue);
            }
        }

        /// <summary>
        /// Vettore Ordini + durate
        /// </summary>
        public Dictionary<int, double> OrderSet { get; set; } = new Dictionary<int, double>();

        /// <summary>
        /// Valore target durate desiderate
        /// </summary>
        public double TargetValue { get; set; } = 0;

        #endregion Public Properties
    }

    /// <summary>
    /// Classe che rappresenta stato ordine ricevuto via REDIS da NESTING
    /// </summary>
    public class orderStatus : baseNestAnsw
    {
        #region Public Properties

        /// <summary>
        /// ID del processo di Nesting in corso (generato in fase di import)
        /// </summary>
        public int BatchID { get; set; }

        #endregion Public Properties
    }

    /// <summary>
    /// Struttura Item passata a NESTING
    /// </summary>
    public class Part
    {
        #region Public Properties

        /// <summary>
        /// Path del disegno CAD dell'item da produrre x NESTING
        /// </summary>
        public string CadFilePath { get; set; }

        /// <summary>
        /// ID del materiale dell'item
        /// </summary>
        public int MatId { get; set; }

        /// <summary>
        /// Parametri opzionali (es x risposta NESTING)
        /// </summary>
        public Dictionary<string, string> OptParameters { get; set; } = null;

        /// <summary>
        /// Codice Datamatrix dell'ITEM
        /// </summary>
        public string PartDtmx { get; set; } = "";

        /// <summary>
        /// Codice ITEM esterno da cliente (HFA)
        /// </summary>
        public string PartExtCode { get; set; }

        /// <summary>
        /// Cod ITEM di NKC
        /// </summary>
        public int PartId { get; set; } = 0;

        /// <summary>
        /// Quantità di Item per SINGOLO ordine
        /// </summary>
        public int PartQty { get; set; }

        #endregion Public Properties
    }

    /// <summary>
    /// Descrizione di un ITEM in fase di scarico
    /// </summary>
    public class PartUnload : Part
    {
        #region Public Properties

        /// <summary>
        /// Destinazione dell'item
        /// </summary>
        public ItemDest NextDest { get; set; } = ItemDest.Undef;

        /// <summary>
        /// Elenco di Secop opzionali (es T-NUT, RoundEdge)
        /// </summary>
        public List<string> SecOp { get; set; } = new List<string>();

        /// <summary>
        /// Stato dell'item
        /// </summary>
        public ItemStatus Status { get; set; } = ItemStatus.Undef;

        #endregion Public Properties
    }

    /// <summary>
    /// Classe che rappresenta i BUNK da lavorare
    /// </summary>
    public class ProdBunk
    {
        #region Public Properties

        /// <summary>
        /// Identificativo univoco BUNK / Stack
        /// </summary>
        public int BunkId { get; set; }

        /// <summary>
        /// Codice dataMatrix del BUNK
        /// </summary>
        public string DataMatrix { get; set; }

        /// <summary>
        /// Data inizio processing dello Stack
        /// </summary>
        public DateTime DtEnd { get; set; }

        /// <summary>
        /// Data inizio processing del BUNK
        /// </summary>
        public DateTime DtStart { get; set; }

        /// <summary>
        /// Numero di Sheets da lavorare
        /// </summary>
        public int NumSheets
        {
            get
            {
                int answ = 0;
                try
                {
                    answ = SheetList.Count;
                }
                catch
                { }
                return answ;
            }
        }

        /// <summary>
        /// Elenco dei pannelli(sheets) dello Stack
        /// </summary>
        public List<ProdSheet> SheetList { get; set; }

        /// <summary>
        /// Stato dello Stack di pannelli
        /// </summary>
        public CStatus Status { get; set; }

        #endregion Public Properties
    }

    /// <summary>
    /// Singolo Pannello IN LAVORAZIONE
    /// </summary>
    public class ProdSheet
    {
        #region Public Properties

        /// <summary>
        /// Tempi processo x fase CNC
        /// </summary>
        public WorkData Machining { get; set; }

        /// <summary>
        /// Materiale
        /// </summary>
        public MaterialData Material { get; set; }

        /// <summary>
        /// Tempi processo x fase printing
        /// </summary>
        public WorkData Printing { get; set; }

        /// <summary>
        /// Identificativo univoco pannello
        /// </summary>
        public int SheetId { get; set; }

        /// <summary>
        /// Stato del pannello
        /// </summary>
        public PStatus Status { get; set; }

        /// <summary>
        /// Tempi processo x scarico
        /// </summary>
        public WorkData Unloading { get; set; }

        #endregion Public Properties
    }

    /// <summary>
    /// Estensione classe sheet comprensiva di BunkId
    /// </summary>
    public class ProdSheetExt : ProdSheet
    {
        #region Public Properties

        /// <summary>
        /// Identificativo univoco BUNK / Stack
        /// </summary>
        public int BunkId { get; set; }

        /// <summary>
        /// INDICE del pannello (valido per BUNK)
        /// </summary>
        public int SheetIndex { get; set; }

        #endregion Public Properties
    }

    /// <summary>
    /// Classe che rappresenta un insieme di Sheet da lavorare (contenuti in 1 o + bunk)
    /// </summary>
    public class SheetWorkList
    {
        #region Public Properties

        /// <summary>
        /// Codice impianto/macchina
        /// </summary>
        public string Machine { get; set; } = "WRK000";

        /// <summary>
        /// Numero di Sheets da lavorare
        /// </summary>
        public int NumSheets
        {
            get
            {
                int answ = 0;
                try
                {
                    answ = SheetList.Count;
                }
                catch
                { }
                return answ;
            }
        }

        /// <summary>
        /// Elenco dei pannelli (sheets) in lavorazione
        /// </summary>
        public List<ProdSheetExt> SheetList { get; set; }

        #endregion Public Properties
    }

    /// <summary>
    /// Dati della lavorazione
    /// </summary>
    public class WorkData
    {
        #region Public Properties

        /// <summary>
        /// Data fine processing
        /// </summary>
        public DateTime? DtEnd { get; set; }

        /// <summary>
        /// Data inizio processing
        /// </summary>
        public DateTime? DtStart { get; set; }

        /// <summary>
        /// Percorso del programma da eseguire
        /// </summary>
        public string ProgramPath { get; set; }

        /// <summary>
        /// Indica che la lavorazione è stata eseguita con successo (default = true)
        /// </summary>
        public bool Success { get; set; }

        /// <summary>
        /// Tempo di lavorazione in minuti decimali
        /// </summary>
        public double WorkTimeMin
        {
            get
            {
                double answ = 0;
                if (DtStart != null && DtEnd != null)
                {
                    try
                    {
                        answ = ((DateTime)DtEnd).Subtract((DateTime)DtStart).TotalMinutes;
                    }
                    catch
                    { }
                }
                return answ;
            }
        }

        #endregion Public Properties
    }
}