using bdHerramientaCACOA.db;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static bdHerramientaCACOA.CASA;
using bdHerramientaCACOA.extensiones;
using System.Text.Json;
using bdHerramientaCACOA.HerramientaUrban;

namespace bdHerramientaCACOA.HerramientaURBAN
{
    public partial class URBAN
    {
        public string NombreSimulacion { get; set; } = "CASA Urbanismo " + DateTime.Now;

        private CASADespachoProfesional _DespachoProfesional = new CASADespachoProfesional();
        public CASADespachoProfesional DespachoProfesional
        {
            get { return _DespachoProfesional; }
            set { _DespachoProfesional = value; }
        }

        private URBANTrabajoProfesional _TrabajoProfesional = new URBANTrabajoProfesional();
        public URBANTrabajoProfesional TrabajoProfesional
        {
            get { return _TrabajoProfesional; }
            set { _TrabajoProfesional = value; }
        }

         private URBANCostesProduccion _CostesProduccion = new URBANCostesProduccion();
        public URBANCostesProduccion CostesProduccion
        {
            get { return _CostesProduccion; }
            set
            {
                _CostesProduccion = value;
            }
        }

        public EnumeradosURBAN Enumerados { get; set; } = new EnumeradosURBAN();
        public VariablesCASA Variables { get; set; } = new VariablesCASA();


        #region Carga de Datos
        public void CargarVariables(bdHerramientaCACOA.dbcontext.tsHerramientasCACOA bd)
        {
            Variables.anyo = (int)bd.enumeraciones.First(x => x.Codigo == "VARCASA.ANYO").ValorNumerico1;
            Variables.ConvenioColectivo = (string)bd.enumeraciones.First(x => x.Codigo == "VARCASA.CONCOL").ValorAlfabetico2;
            Variables.JornadaLaboralHoraSemana = (int)bd.enumeraciones.First(x => x.Codigo == "VARCASA.JORLABHS").ValorNumerico1;
            Variables.DiasLaborales = (int)bd.enumeraciones.First(x => x.Codigo == "VARCASA.DIASLAB").ValorNumerico1;
            Variables.JornadaLaboralEstTrabajadores = (int)bd.enumeraciones.First(x => x.Codigo == "VARCASA.JORLABESTTRAB").ValorNumerico1;
            Variables.JornadaLaboralAnual = (int)bd.enumeraciones.First(x => x.Codigo == "VARCASA.JORLABANUAL").ValorNumerico1;
            Variables.HorasProduccionMedia = (double)bd.enumeraciones.First(x => x.Codigo == "VARCASA.HORPRODMEDIA").ValorNumerico1;
            Variables.CosteSegSocial = (double)bd.enumeraciones.First(x => x.Codigo == "VARCASA.COSTESSEGSOCIAL").ValorNumerico1;
            Variables.CostesVariables = (double)bd.enumeraciones.First(x => x.Codigo == "VARCASA.COSTESVARIABLES").ValorNumerico1;
            Variables.OtrosCostes = (double)bd.enumeraciones.First(x => x.Codigo == "VARCASA.OTROSCOSTES").ValorNumerico1;
        }
        public void RellenarCamposExtra(dbcontext.tsHerramientasCACOA bd, bool esClonar)
        {
            CargarVariables(bd);
            CargarEnumerados(bd, esClonar);
            //por defecto periodoMensual
            enumeraciones perMensual = bd.enumeraciones.First(x => x.Codigo == "PERIODOS.MENSUAL");
            //Cargamos los costes indirectos
            var grupoCostesIndirectos = bd.gruposenumeraciones.FirstOrDefault(x => x.Grupo == "CI");
            var listaCosteIndirectos = Utilidades.devolverListadoOrdenadoEnumeracion(bd, grupoCostesIndirectos.idGrupoEnumeracion);
            foreach (enumeraciones enu in listaCosteIndirectos)
            {
                if (!DespachoProfesional.CostesIndirectos.Any(x => x.Concepto == enu.ValorAlfabetico1))
                {
                    CosteIndirecto ci = new CosteIndirecto();
                    ci.idCosteIndirecto = enu.idEnumeracion;
                    ci.Concepto = enu.ValorAlfabetico1;
                    ci.idPeriodicidad = perMensual.idEnumeracion;
                    ci.valorPeriodo = (double)perMensual.ValorNumerico1;
                    ci.idPuntoInformacion = string.IsNullOrEmpty(enu.ValorAlfabetico4) ? 0 : int.Parse(enu.ValorAlfabetico4);
                    DespachoProfesional.CostesIndirectos.Add(ci); 
                        }
            }
            checkListCostIndirectos(listaCosteIndirectos);

            Enumerados.PuntosInformacion = bd.puntosinformacion.Where(x => x.idTipoHerramienta == 34 || x.idTipoHerramienta == 31).ToList();

            //Cargamos las Fases
            var grupoFases = bd.gruposenumeraciones.FirstOrDefault(x => x.Grupo == "FASURB");
            var listaFases = bd.enumeraciones.Where(x => x.idGrupoEnumeracion == grupoFases.idGrupoEnumeracion).ToList();
            foreach (enumeraciones enu in listaFases)
            {
                if (!TrabajoProfesional.FasesTrabajoProfesional.Any(x => x.idFase == enu.idEnumeracion))
                {
                    FasesURBAN ft = new FasesURBAN();
                    ft.idFase = enu.idEnumeracion;
                    ft.Codigo = enu.Codigo;
                    ft.Denominacion = enu.ValorAlfabetico1;
                    ft.Porcentaje = (double)enu.ValorNumerico1;

                    TrabajoProfesional.FasesTrabajoProfesional.Add(ft);
                }
            }
            checkListFases(listaFases);

            Enumerados.FasesTrabajo= JsonSerializer.Deserialize<List<FasesURBAN>>(JsonSerializer.Serialize(TrabajoProfesional.FasesTrabajoProfesional));
        }

        private void checkListCostIndirectos(List<enumeraciones> listaCostesIndirectos)
        {
            var itemsAEliminar = DespachoProfesional.CostesIndirectos
                .Where(item => !listaCostesIndirectos.Any(x => x.ValorAlfabetico1 == item.Concepto))
                .ToList();

            foreach (var item in itemsAEliminar)
            {
                DespachoProfesional.CostesIndirectos.Remove(item);
            }
        }


        private void checkListFases(List<enumeraciones> listaFasesUrban)
        {
            var itemsAEliminar = TrabajoProfesional.FasesTrabajoProfesional
                .Where(item => !listaFasesUrban.Any(x => x.idEnumeracion == item.idFase))
                .ToList();

            foreach (var item in itemsAEliminar)
            {
                TrabajoProfesional.FasesTrabajoProfesional.Remove(item);
            }
        }

        public void CargarEnumerados(dbcontext.tsHerramientasCACOA bd, bool esClonar) {
            var grupoPeriodos = bd.gruposenumeraciones.FirstOrDefault(x => x.Grupo == "PERIODOS");
            Enumerados.Periodos = ListaEnumeracionCASA(bd.enumeraciones.Where(x => x.idGrupoEnumeracion == grupoPeriodos.idGrupoEnumeracion).ToList());

            var grupoTipDocumento = bd.gruposenumeraciones.FirstOrDefault(x => x.Grupo == "TIPODOCU");
            Enumerados.TiposDeDocumentos = ListaEnumeracionCASA(bd.enumeraciones.Where(x => x.idGrupoEnumeracion == grupoTipDocumento.idGrupoEnumeracion).ToList());

            if (!esClonar)
            {
                var grupoInstrumentos = bd.gruposenumeraciones.FirstOrDefault(x => x.Grupo == "INNINSTR");
                Enumerados.ListaInstrumentos = ListaEnumeracionCASA(bd.enumeraciones.Where(x => x.idGrupoEnumeracion == grupoInstrumentos.idGrupoEnumeracion).ToList());
            }

            var grupoVariables = bd.gruposenumeraciones.FirstOrDefault(x => x.Grupo == "CVURB");
            Enumerados.ListaCostesVariables = ListaEnumeracionCASA(bd.enumeraciones.Where(x => x.idGrupoEnumeracion == grupoVariables.idGrupoEnumeracion).ToList());


            List<tipoproyectos> lp= bd.tipoproyectos.ToList();
            List<tipoproyectosURBAN> lpu = new List<tipoproyectosURBAN>();
            foreach (tipoproyectos tp in lp) {
                tipoproyectosURBAN tpu= new tipoproyectosURBAN();
                tpu.idtipoproyectos = tp.idtipoproyectos;
                tpu.idTipoDocumento = tp.idTipoDocumento;
                tpu.Descripcion = tp.Descripcion;
                tpu.Abreviatura = tp.Abreviatura;
                lpu.Add(tpu);
            }
            Enumerados.TiposProyecto = lpu;

            List<tipoproyecto_documentacion> ltpd= bd.tipoproyecto_documentacion.ToList();
            List<tipoproyecto_documentacionURBAN> ltpdu = new List<tipoproyecto_documentacionURBAN>();
            foreach (tipoproyecto_documentacion tpd in ltpd)
            {
                tipoproyecto_documentacionURBAN tpdu = new tipoproyecto_documentacionURBAN();
                tpdu.idtipoproyecto_documentacion = tpd.idtipoproyecto_documentacion;
                tpdu.idtipoproyecto = tpd.idtipoproyecto;
                tpdu.iddocumentacion = tpd.iddocumentacion;
                tpdu.esMinima = tpd.esMinima;
                tpdu.esOpcional = tpd.esOpcional;
                tpdu.esNecesario = tpd.esNecesario;
                ltpdu.Add(tpdu);
            }

            Enumerados.TipoProy_Documentacion = ltpdu;

            Enumerados.documentacion = documentacionAUrban(bd.documentacion.ToList());

        }
        #endregion


        #region Funciones Despacho Profesional
        //Funciones Despacho Profesional
        public double CalcularHorasTotalesProduccion()
        {
            if (DespachoProfesional.Trabajadores.Count == 0)
            {
                return 0;
            }
            return DespachoProfesional.Trabajadores.Sum(x => x.HorasProduccion);
        }
        public double CalcularCostesDirectosAnuales()
        {
            return DespachoProfesional.Trabajadores.Sum(x => x.CosteAnualTotal);
        }
        public double CalcularTotalCostesIndirectos()
        {
            return DespachoProfesional.CostesIndirectos.Sum(x => x.coste);
        }

        public double CalcularCostesDirectos()
        {
            if (DespachoProfesional.HorasTotalesProduccion == 0 || DespachoProfesional.CostesDirectosAnuales == 0)
            {
                return 0;
            }

            return Math.Round((DespachoProfesional.CostesDirectosAnuales / DespachoProfesional.HorasTotalesProduccion), 2, MidpointRounding.AwayFromZero);
        }
        public double CalcularTasaCostesIndirectos()
        {
            if (DespachoProfesional.HorasTotalesProduccion == 0)
            {
                return 0;
            }
            else
            {
                return Math.Round((DespachoProfesional.TotalCostesIndirectos / DespachoProfesional.HorasTotalesProduccion), 2, MidpointRounding.AwayFromZero);
            }
        }
        public double CalcularCosteHoraDespachoProfesional()
        {
            return Math.Round((DespachoProfesional.CostesDirectos + DespachoProfesional.TasaCostesIndirectos), 2, MidpointRounding.AwayFromZero);
        }

        public void CalcularCosteTotalAnual(Trabajador trab)
        {
            trab.CosteAnualTotal = (trab.NumTrabajadores * trab.CosteAnual).DosDecimales();
        }
        public void CalcularHorasProduccion(Trabajador trab)
        {
            trab.HorasProduccion = (Variables.JornadaLaboralAnual * trab.JornadaLaboral / Variables.JornadaLaboralHoraSemana * trab.NumTrabajadores * (trab.PorcentajeProduccion / 100)).DosDecimales();
        }
        public void InsertarTrabajador(Trabajador trab)
        {
            CalcularCosteTotalAnual(trab);
            CalcularHorasProduccion(trab);
            DespachoProfesional.Trabajadores.Add(trab);

            CalcularFinales();
        }
        public void ActualizarTrabajador(Trabajador trab)
        {
            CalcularCosteTotalAnual(trab);
            CalcularHorasProduccion(trab);

            int indice = DespachoProfesional.Trabajadores.ToList().IndexOf(trab);
            DespachoProfesional.Trabajadores[indice] = trab;

            CalcularFinales();
        }
        public void EliminarTrabajador(Trabajador trab)
        {
            DespachoProfesional.Trabajadores.Remove(trab);

            CalcularFinales();
        }


        public void ActualizarCosteIndirecto(CosteIndirecto ci)
        {
            var periodo = Enumerados.Periodos.First(x => x.idEnumeracion == ci.idPeriodicidad);
            ci.idPeriodicidad = periodo.idEnumeracion;
            ci.valorPeriodo = (double)periodo.ValorNumerico1;
            ci.coste = ci.importe * ci.valorPeriodo;

            int indice = DespachoProfesional.CostesIndirectos.ToList().IndexOf(ci);
            DespachoProfesional.CostesIndirectos[indice] = ci;

            CalcularFinales();
        }
        public void LimpiarCosteIndirecto(CosteIndirecto ci)
        {
            ci.importe = 0;
            ci.coste = 0;
        }


        public void CalcularFinales()
        {
            DespachoProfesional.CostesDirectosAnuales = CalcularCostesDirectosAnuales();
            DespachoProfesional.HorasTotalesProduccion = CalcularHorasTotalesProduccion();

            DespachoProfesional.TotalCostesIndirectos = CalcularTotalCostesIndirectos();
            DespachoProfesional.TasaCostesIndirectos = CalcularTasaCostesIndirectos();

            DespachoProfesional.CostesDirectos = CalcularCostesDirectos();
            DespachoProfesional.CosteHoraDespachoProfesional = CalcularCosteHoraDespachoProfesional();
            CalcularCostesProduccion();
        }


        #endregion

        #region parsearObjetos
        public List<enumeracionesCASA> ListaEnumeracionCASA(List<enumeraciones> lista)
        {

            List<enumeracionesCASA> lu = new List<enumeracionesCASA>();
            foreach (enumeraciones enu in lista)
            {
                lu.Add(EnumeracionACASA(enu));
            }
            return lu;
        }
        public enumeracionesCASA EnumeracionACASA(enumeraciones enu)
        {
            return new enumeracionesCASA()
            {
                idEnumeracion = enu.idEnumeracion,
                idGrupoEnumeracion = enu.idGrupoEnumeracion,
                Codigo = enu.Codigo,
                Descripcion = enu.Descripcion,
                ValorAlfabetico1 = enu.ValorAlfabetico1,
                ValorAlfabetico2 = enu.ValorAlfabetico2,
                ValorNumerico1 = enu.ValorNumerico1
            };
        }
        #endregion


        //public double CalcularIncremento()
        //{
        //    double incremento = 3.5;

        //    var listaPlazos = TrabajoProfesional.FasesTrabajo.Where(x => x.Porcentaje > 0 && x.PlazoMinimo != null).ToList();
        //    if (listaPlazos.Count > 0)
        //    {
        //        double meses = (double)listaPlazos.Sum(x => x.PlazoMinimo);
        //        if (CostesProduccion.PlazoPresentacionDocumentos < meses)
        //        {
        //            return (meses - CostesProduccion.PlazoPresentacionDocumentos) * incremento;
        //        }
        //        else
        //        {
        //            return 0;
        //        }
        //    }
        //    else
        //    {
        //        return 0;
        //    }

        //}
    }
}
