using System;
using System.Collections.Generic;
using System.Drawing.Imaging;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Mysqlx.Expr;
using bdHerramientaCACOA.db;
using System.Numerics;
using Google.Protobuf.WellKnownTypes;
using tsUtilidades.Enumeraciones;
using MySqlX.XDevAPI.Common;
using Microsoft.EntityFrameworkCore.Query.Internal;
using static bdHerramientaCACOA.CASA;
using System.ComponentModel.DataAnnotations;
using bdHerramientaCACOA.extensiones;
using bdHerramientaCACOA.dbcontext;

namespace bdHerramientaCACOA
{
    public class CASA
    {
        public class VariablesCASA
        {
            public int anyo { get; set; } = 2025;
            public string ConvenioColectivo { get; set; } = "of. y Desp Sevilla";
            public int JornadaLaboralHoraSemana { get; set; } = 40;
            public int DiasLaborales { get; set; } = 249;
            public int JornadaLaboralEstTrabajadores { get; set; } = 1826;
            public int JornadaLaboralAnual { get; set; } = 1800;
            public double HorasProduccionMedia { get; set; } = 80;
            public double CosteSegSocial { get; set; } = 0.3215;
            public double CostesVariables { get; set; } = 0.035;
            public double OtrosCostes { get; set; } = 0.03;
        }
        public class EnumeradosCASA {
            public List<puntosinformacion> PuntosInformacion { get; set; } = new List<puntosinformacion>();
            public  List<enumeracionesCASA> Periodos { get; set; } = new List<enumeracionesCASA>();
            public  List<enumeracionesCASA> GruposTipologias { get; set; } = new List<enumeracionesCASA>();
            public  List<enumeracionesCASA> Intervenciones { get; set; } = new List<enumeracionesCASA>();
            public  List<enumeracionesCASA> ListaOtrosTrabajos { get; set; } = new List<enumeracionesCASA>();
            public  List<enumeracionesCASA> ListaCostesVariables { get; set; } = new List<enumeracionesCASA>();
            public  List<tipologiasCASA> Tipologias { get; set; } = new List<tipologiasCASA>();
            public  List<factorescorreccionCASA> ListaFactoresCorrecion { get; set; } = new List<factorescorreccionCASA>();
            public  List<conveniocolectivoCASA> ListaConvenioColectivo { get; set; } = new List<conveniocolectivoCASA>();
            public  List<enumeracionesCASA> ListaPuestosTrabajo { get; set; } = new List<enumeracionesCASA>();
            public List<FasesTrabajo> FasesTrabajoOriginal { get; set; } = new List<FasesTrabajo>() { };
            public List<tipologiasCASA> TipologiasPorGrupo(int idgrupo) {
                return Tipologias.Where(x => x.idGrupoTip == idgrupo).ToList();
            }
            public  List<factorescorreccionCASA> FactoresCorreccionPorGrupo(int id) {
                return ListaFactoresCorrecion.Where(x => x.idEnumeracion == id).OrderBy(x=> x.Coeficiente).ToList();
            }

        }

        public string NombreSimulacion { get; set; } = "CASA Edificación " + DateTime.Now;

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

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

        private CASACostesProduccion _CostesProduccion = new CASACostesProduccion();
        public CASACostesProduccion CostesProduccion
        {
            get { return _CostesProduccion; }
            set
            {
                _CostesProduccion = value;
            }
        }
        public EnumeradosCASA Enumerados { get; set; } = new EnumeradosCASA();
        public VariablesCASA Variables { get; set; } = new VariablesCASA();

        #region Carga de Datos
        public void RellenarCamposExtra(bdHerramientaCACOA.dbcontext.tsHerramientasCACOA bd)
        {
            CargarVariables(bd);
            //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 == 31).ToList();


            Enumerados.ListaFactoresCorrecion = ListaFactoresCorreccionCASA(bd.factorescorreccion.ToList());
            //Cargamos los coeficientes correctores
            //Complejidad
            var grupoFacCom = bd.gruposenumeraciones.FirstOrDefault(x => x.Grupo == "FACCOMP");
            var listaFacCom = Utilidades.devolverListadoOrdenadoEnumeracion(bd, grupoFacCom.idGrupoEnumeracion);
            foreach (enumeraciones enu in listaFacCom)
            {
                if (!TrabajoProfesional.FactoresComplejidad.Any(x => x.Nombre == enu.ValorAlfabetico1))
                {
                    CoeficientesCorrectores fc = new CoeficientesCorrectores();
                    fc.idTipoFactor = enu.idEnumeracion;
                    fc.Nombre = enu.ValorAlfabetico1;
                    fc.idCorrecion = Enumerados.FactoresCorreccionPorGrupo(fc.idTipoFactor).First(x => x.Coeficiente == 0).idFactorCorreccion;
                    fc.idPuntoInformacion = string.IsNullOrEmpty(enu.ValorAlfabetico4) ? 0 : int.Parse(enu.ValorAlfabetico4);

                    TrabajoProfesional.FactoresComplejidad.Add(fc);
                }
            }
            //Cargamos los coeficientes correctores
            //Rendimiento
            var grupoFacRend = bd.gruposenumeraciones.FirstOrDefault(x => x.Grupo == "FACREND");
            var listaFacRend = Utilidades.devolverListadoOrdenadoEnumeracion(bd, grupoFacRend.idGrupoEnumeracion); ;
            foreach (enumeraciones enu in listaFacRend)
            {
                if (!TrabajoProfesional.FactoresRendimiento.Any(x => x.Nombre == enu.ValorAlfabetico1))
                {
                    CoeficientesCorrectores fc = new CoeficientesCorrectores();
                    fc.idTipoFactor = enu.idEnumeracion;
                    fc.Nombre = enu.ValorAlfabetico1;
                    fc.idCorrecion = Enumerados.FactoresCorreccionPorGrupo(fc.idTipoFactor).First(x => x.Coeficiente == 0).idFactorCorreccion;
                    fc.idPuntoInformacion = string.IsNullOrEmpty(enu.ValorAlfabetico4) ? 0 : int.Parse(enu.ValorAlfabetico4);
                    TrabajoProfesional.FactoresRendimiento.Add(fc);
                }
            }

            checkListFactores(listaFacCom, listaFacRend);

            //Cargamos las Fases
            var grupoFases = bd.gruposenumeraciones.FirstOrDefault(x => x.Grupo == "FASES");
            var listaFases = Utilidades.devolverListadoOrdenadoEnumeracion(bd, grupoFases.idGrupoEnumeracion);
            foreach (enumeraciones enu in listaFases)
            {
                if (!Enumerados.FasesTrabajoOriginal.Any(x => x.Denominacion == enu.ValorAlfabetico1))
                {
                    FasesTrabajo ft = new FasesTrabajo();
                ft.idFase = enu.idEnumeracion;
                ft.Codigo = enu.Codigo;
                ft.Denominacion = enu.ValorAlfabetico1;
                ft.Porcentaje = (double)enu.ValorNumerico1;
                ft.PlazoMinimo = enu.ValorNumerico2 == null ? null : (double)enu.ValorNumerico2;
                TrabajoProfesional.FasesTrabajo.Add(ft);

                var copia = new FasesTrabajo
                {
                    idFase = ft.idFase,
                    Codigo = ft.Codigo,
                    Denominacion = ft.Denominacion,
                    Porcentaje = ft.Porcentaje,
                    PlazoMinimo = ft.PlazoMinimo
                };
                Enumerados.FasesTrabajoOriginal.Add(copia);
                }

            }

            //Cargamos los costes variables
            var grupoCostesVariables = bd.gruposenumeraciones.FirstOrDefault(x => x.Grupo == "CV");
            Enumerados.ListaCostesVariables = ListaEnumeracionCASA(Utilidades.devolverListadoOrdenadoEnumeracion(bd, grupoCostesVariables.idGrupoEnumeracion).ToList());
            //foreach (enumeraciones enu in listaCostesVariables)
            //{
            //    CosteVariable cv = new CosteVariable();
            //    cv.idCoste = enu.idEnumeracion;
            //    cv.Denominacion = enu.ValorAlfabetico1;

            //    CostesProduccion.ListaCostesVariables.Add(cv);
            //}

            //Cargamos la lista de otros costes de trabajo
            var grupoOtrosTrab = bd.gruposenumeraciones.FirstOrDefault(x => x.Grupo == "OTROSTRAB");
            Enumerados.ListaOtrosTrabajos = ListaEnumeracionCASA(Utilidades.devolverListadoOrdenadoEnumeracion(bd, grupoOtrosTrab.idGrupoEnumeracion).ToList());
            //foreach (enumeraciones enu in listaOtrosTrab)
            //{
            //    OtrosTrabajos ot = new OtrosTrabajos();
            //    ot.idTrabajo = enu.idEnumeracion;
            //    ot.Denominacion = enu.ValorAlfabetico1;

            //    CostesProduccion.OtrosTrabajos.Add(ot);
            //}

            var grupoPuestoTrabajo = bd.gruposenumeraciones.FirstOrDefault(x => x.Grupo == "PUESTOTRABAJO");
            Enumerados.ListaPuestosTrabajo =ListaEnumeracionCASA(Utilidades.devolverListadoOrdenadoEnumeracion(bd, grupoPuestoTrabajo.idGrupoEnumeracion).ToList());

            var grupoPeriodos = bd.gruposenumeraciones.FirstOrDefault(x => x.Grupo == "PERIODOS");
            Enumerados.Periodos = ListaEnumeracionCASA(Utilidades.devolverListadoOrdenadoEnumeracion(bd, grupoPeriodos.idGrupoEnumeracion).ToList());

            var grupoIntervencion = bd.gruposenumeraciones.FirstOrDefault(x => x.Grupo == "INTERVENCION");
            Enumerados.Intervenciones = ListaEnumeracionCASA(Utilidades.devolverListadoOrdenadoEnumeracion(bd, grupoIntervencion.idGrupoEnumeracion).ToList());

            var grupoTipologias = bd.gruposenumeraciones.FirstOrDefault(x => x.Grupo == "GRUPTIP");
            Enumerados.GruposTipologias = ListaEnumeracionCASA(Utilidades.devolverListadoOrdenadoEnumeracion(bd, grupoTipologias.idGrupoEnumeracion).ToList());

            Enumerados.ListaConvenioColectivo = ListaConvColectivoCASA( bd.conveniocolectivo.Where(x => x.idProvincia == "41").ToList());

            Enumerados.Tipologias = ListaTipologiasCASA( bd.tipologias.ToList());
        }

        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 checkListFactores(List<enumeraciones> listaFacCom, List<enumeraciones> listaFacRendimiento)
        {
            var itemsCompleAEliminar = TrabajoProfesional.FactoresComplejidad
                .Where(item => !listaFacCom.Any(x => x.ValorAlfabetico1 == item.Nombre))
                .ToList();

            foreach (var item in itemsCompleAEliminar)
            {
                TrabajoProfesional.FactoresComplejidad.Remove(item);
            }



            var itemsRendiAEliminar = TrabajoProfesional.FactoresRendimiento
                .Where(item => !listaFacRendimiento.Any(x => x.ValorAlfabetico1 == item.Nombre))
                .ToList();

            foreach (var item in itemsRendiAEliminar)
            {
                TrabajoProfesional.FactoresRendimiento.Remove(item);
            }
        }
        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;
        }
        #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();
        }


        public void InsertarGrupoTrabajador(GrupoTrabajador gt)
        {
            RellenarCalcularDatos(gt);
            DespachoProfesional.CostesPersonal.GrupoTrabajadores.Add(gt);
        }
        public void ActualizarGrupoTrabajador(GrupoTrabajador gt)
        {
            RellenarCalcularDatos(gt);
            int indice = DespachoProfesional.CostesPersonal.GrupoTrabajadores.ToList().IndexOf(gt);
            DespachoProfesional.CostesPersonal.GrupoTrabajadores[indice] = gt;
        }
        public void EliminarGrupoTrabajo(GrupoTrabajador gt)
        {
            DespachoProfesional.CostesPersonal.GrupoTrabajadores.Remove(gt);
        }
        public void RellenarCalcularDatos(GrupoTrabajador gt)
        {
            //Nota, que esto no se esta usando pero si se usa igual hay que revisar decimales
            conveniocolectivoCASA cc = Enumerados.ListaConvenioColectivo.First(x => x.idEnumeracion == gt.idCategoriaProfesional);

            gt.TotalDevengado = Math.Round(cc.Convenio, 2, MidpointRounding.AwayFromZero);
            gt.segSocialEmpresa = Math.Round((gt.TotalDevengado + gt.Complementos) * 0.3251, 2, MidpointRounding.AwayFromZero);
            gt.CosteAnualIndividual = Math.Round((((gt.TotalDevengado + gt.Complementos) * gt.numPagasAnuales + gt.segSocialEmpresa * 12) * gt.HorasJornadaLaboral / 40), 2, MidpointRounding.AwayFromZero);
            gt.HorasAnuales = Variables.JornadaLaboralAnual;
            gt.PorcentajeProduccion = Variables.HorasProduccionMedia;
            gt.PorcentajeAdministración = 100 - gt.PorcentajeProduccion;
            gt.HorasProduccion = gt.HorasAnuales * gt.PorcentajeAdministración / 100;
        }
        #endregion

        #region Funciones Trabajo Profesional
        //Funciones Trabajo Profesional
        public void InsertarUso(UsosTipologia uso)
        {
            RellenarDatosUsoExtra(uso);
            TrabajoProfesional.Usos.Add(uso);
            CalcularHorasTPE();
        }
        public void ActualizarUso(UsosTipologia uso)
        {
            RellenarDatosUsoExtra(uso);
            int indice = TrabajoProfesional.Usos.ToList().IndexOf(uso);
            TrabajoProfesional.Usos[indice] = uso;
            CalcularHorasTPE();
        }
        public void EliminarUso(UsosTipologia uso)
        {
            TrabajoProfesional.Usos.Remove(uso);

            if (TrabajoProfesional.Usos.ToList().Count == 0)
            {
                TrabajoProfesional.HorasTPE = 0;
                TrabajoProfesional.HorasTPEDocumentacion = 0;
                TrabajoProfesional.HorasTPEDireccion = 0;

                CalcularCostesProduccion();
            }
            else
            {
                CalcularHorasTPE();
            }
        }
        public void RellenarDatosUsoExtra(UsosTipologia uso)
        {
            tipologiasCASA tipologia = Enumerados.Tipologias.First(x => x.idTipologia == uso.idTipologia);
            enumeracionesCASA intervencion = Enumerados.Intervenciones.First(x => x.idEnumeracion == uso.idTipoIntervencion);
            uso.CoefTipologia = tipologia.CoeficienteUso;
            uso.SuperficieCoefTipologia = (uso.CoefTipologia * uso.superficie).DosDecimales();
            uso.CoefIntervencion = (double)intervencion.ValorNumerico1;
            uso.SuperficieCoefIntervencion = (uso.CoefIntervencion * uso.superficie).DosDecimales();
        }
        public void CalcularHorasTPE()
        {
            TrabajoProfesional.HorasTPE = CalcularHorasTrabajoProfesionalEdificacion();
            TrabajoProfesional.TotalHorasTPE = CalcularHorasTrabajoProfesionalEdificacion();
            double totalHorasTPEDocu = CalcularHorasTPEDocumentacion();
            TrabajoProfesional.HorasTPEDocumentacion = double.IsNaN(totalHorasTPEDocu) ? 0 : totalHorasTPEDocu;
            double totalHorasTPEDireccion = CalcularHorasTPEDireccion();
            TrabajoProfesional.HorasTPEDireccion = double.IsNaN(totalHorasTPEDireccion) ? 0 : totalHorasTPEDireccion;
            TrabajoProfesional.TotalHorasTPE = totalHorasTPEDocu + totalHorasTPEDireccion;

            TrabajoProfesional.HorasTPEEstimacion = TrabajoProfesional.HorasTPE;
            TrabajoProfesional.HorasTPEDocumentacionEstimacion = TrabajoProfesional.HorasTPEDocumentacion;
            TrabajoProfesional.HorasTPEDireccionEstimacion = TrabajoProfesional.HorasTPEDireccion;

            CalcularCostesProduccion();
        }
        public void CalcularHorasTPEManual(double horasDocu, double horasDireccion)
        {
            TrabajoProfesional.HorasTPEDocumentacion = horasDocu;
            TrabajoProfesional.HorasTPEDireccion = horasDireccion;
            TrabajoProfesional.HorasTPE = horasDocu + horasDireccion;
            TrabajoProfesional.TotalHorasTPE = horasDocu + horasDireccion;
            CalcularCostesProduccion();
        }
        public double CalcularHorasTrabajoProfesionalEdificacion()
        {
            double superficieTotal = CalcularSuperficieTotal();
            double calculoSupT = -0.1375 * Math.Log(superficieTotal) + 2.4;
            double CoefSuperficieTotal = Math.Ceiling(calculoSupT * 100) / 100;
            double CoefTipologiaTotal = Math.Round(CalcularSuperficieCoeficienteTipologiaTotal() / superficieTotal, 2, MidpointRounding.AwayFromZero);
            double CoefIntervencionTotal = Math.Round(CalcularSuperficieCoeficienteIntervencionTotal() / superficieTotal, 2, MidpointRounding.AwayFromZero);
            double FactorCorreccionComplejidad = CalcularFactorComplejidad();
            double FactorCorreccionRendimiento = CalcularFactorRendimiento();
            
            var totalHoras = Math.Round((superficieTotal * CoefSuperficieTotal * CoefTipologiaTotal * CoefIntervencionTotal * FactorCorreccionComplejidad * FactorCorreccionRendimiento), 2, MidpointRounding.AwayFromZero);
            return double.IsNaN(totalHoras) ? 0 : totalHoras;
            //return superficieTotal *  CoefSuperficieTotal * coefTipologiaTotal * coefIntervencionTotal * FactorCorreccionComplejidad * FactorCorreccionRendimiento;
            //return Math.Round((totalHoras * (TrabajoProfesional.FasesTrabajo.Sum(x=>x.Porcentaje)/100)),2,MidpointRounding.AwayFromZero);
        }
        public double CalcularHorasTPEDocumentacion()
        {
            double estudioPrevio = TrabajoProfesional.FasesTrabajo.First(x => x.Codigo == "FASES.ESTPREVIO").Porcentaje;
            double anteproyecto = TrabajoProfesional.FasesTrabajo.First(x => x.Codigo == "FASES.ANTEPROYECTO").Porcentaje;
            double proyectobasico = TrabajoProfesional.FasesTrabajo.First(x => x.Codigo == "FASES.PROYBASICO").Porcentaje;
            double proyectoejecucion = TrabajoProfesional.FasesTrabajo.First(x => x.Codigo == "FASES.PROYEJEC").Porcentaje;
            double suma = estudioPrevio + anteproyecto + proyectobasico + proyectoejecucion;

            var total = Math.Round(((TrabajoProfesional.TotalHorasTPE * suma) / 100), 2, MidpointRounding.AwayFromZero);

            return double.IsNaN(total) ? 0 : total;
        }
        public double CalcularHorasTPEDireccion()
        {
            double direccionObra = TrabajoProfesional.FasesTrabajo.First(x => x.Codigo == "FASES.DIROBRA").Porcentaje;
            double liquidacionObra = TrabajoProfesional.FasesTrabajo.First(x => x.Codigo == "FASES.LIQOBRA").Porcentaje;
            double suma = direccionObra + liquidacionObra;
            return Math.Round(((TrabajoProfesional.TotalHorasTPE * suma) / 100), 2, MidpointRounding.AwayFromZero);
        }

        public void ActualizarFactorComplejidad(CoeficientesCorrectores fc)
        {
            fc.coeficiente = Enumerados.ListaFactoresCorrecion.First(x => x.idFactorCorreccion == fc.idCorrecion).Coeficiente;
            int indice = TrabajoProfesional.FactoresComplejidad.ToList().IndexOf(fc);
            TrabajoProfesional.FactoresComplejidad[indice] = fc;
            CalcularHorasTPE();
        }
        public void ActualizarFactorRendimiento(CoeficientesCorrectores fr)
        {
            fr.coeficiente = Enumerados.ListaFactoresCorrecion.First(x => x.idFactorCorreccion == fr.idCorrecion).Coeficiente;
            int indice = TrabajoProfesional.FactoresRendimiento.ToList().IndexOf(fr);
            TrabajoProfesional.FactoresRendimiento[indice] = fr;
            CalcularHorasTPE();
        }
        public void ActualizarFase(FasesTrabajo ft)
        {
            int indice = TrabajoProfesional.FasesTrabajo.ToList().IndexOf(ft);
            TrabajoProfesional.FasesTrabajo[indice] = ft;

            if (TrabajoProfesional.EsPorUsos == true)
            {
                CalcularHorasTPE();
            }
            else
            {
              
            }
        }

        public void ActualizarFaseCalculo(double horasOriginal)
        { 
            TrabajoProfesional.TotalHorasTPE = horasOriginal;
            TrabajoProfesional.HorasTPE = horasOriginal;
            TrabajoProfesional.HorasTPEDocumentacion = CalcularHorasTPEDocumentacion();
            TrabajoProfesional.HorasTPEDireccion = CalcularHorasTPEDireccion();
            TrabajoProfesional.HorasTPE = TrabajoProfesional.HorasTPEDocumentacion + TrabajoProfesional.HorasTPEDireccion;
            TrabajoProfesional.TotalHorasTPE = TrabajoProfesional.HorasTPEDocumentacion + TrabajoProfesional.HorasTPEDireccion;
        }

        public double CalcularSuperficieTotal()
        {
            return TrabajoProfesional.Usos.Sum(x => x.superficie);
        }
        public double CalcularCoeficienteTipologiaTotal()
        {
            return TrabajoProfesional.Usos.Sum(x => x.CoefTipologia);
        }
        public double CalcularCoeficienteIntervencionTotal()
        {
            return TrabajoProfesional.Usos.Sum(x => x.CoefIntervencion);
        }
        public double CalcularSuperficieCoeficienteTipologiaTotal()
        {
            return TrabajoProfesional.Usos.Sum(x => x.SuperficieCoefTipologia);
        }
        public double CalcularSuperficieCoeficienteIntervencionTotal()
        {
            return TrabajoProfesional.Usos.Sum(x => x.SuperficieCoefIntervencion);
        }
        public double CalcularFactorComplejidad()
        {
            return 1 + TrabajoProfesional.FactoresComplejidad.Sum(x => x.coeficiente);
        }
        public double CalcularFactorRendimiento()
        {
            return 1 + TrabajoProfesional.FactoresRendimiento.Sum(x => x.coeficiente);
        }


        public double CalcularTotalFases()
        {
            return TrabajoProfesional.FasesTrabajo.Sum(x => x.Porcentaje);
        }

        #endregion

        #region Funciones Costes Produccion
        //Funciones Costes Produccion
        public void InsertarCostesVariables(CosteVariable cv)
        {
            CostesProduccion.ListaCostesVariables.Add(cv);
            CalcularCostesProduccion();
        }
        public void ActualizarCostesVariables(CosteVariable cv)
        {
            int indice = CostesProduccion.ListaCostesVariables.ToList().IndexOf(cv);
            CostesProduccion.ListaCostesVariables[indice] = cv;

            CalcularCostesProduccion();
        }

        public void EliminarCostesVariables(CosteVariable cv)
        {
            CostesProduccion.ListaCostesVariables.Remove(cv);
            CalcularCostesProduccion();
        }

        //Funciones Otros Trabajos

        public void InsertarOtrosTrabajos(OtrosTrabajos ot)
        {
            CostesProduccion.OtrosTrabajos.Add(ot);
            CalcularCostesProduccion();
        }

        public void EliminarOtrosTrabajos(OtrosTrabajos ot)
        {
            CostesProduccion.OtrosTrabajos.Remove(ot);
            CalcularCostesProduccion();
        }

        public void ActualizarOtrosTrabajos(OtrosTrabajos ot)
        {
            int indice = CostesProduccion.OtrosTrabajos.ToList().IndexOf(ot);
            CostesProduccion.OtrosTrabajos[indice] = ot;

            CalcularCostesProduccion();
        }
        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;
            }

        }

        public double CalcularCostesTotales()
        {
            return CostesProduccion.ListaCostesVariables.Sum(x => x.Coste);
        }
        public double CalcularTotalOtrosTrabajos()
        {
            return CostesProduccion.OtrosTrabajos.Sum(x => x.Coste);
        }
        public void CalcularCostesProduccion()
        {
            //€/H
            if (CostesProduccion.EsCalculado)
            {
                double chtp = CalcularHorasTotalesProduccion();
                if (chtp == 0)
                {
                    CostesProduccion.CostesVariables = 0;
                }
                else {
                    CostesProduccion.CostesVariables = Math.Round(CalcularCostesTotales() / CalcularHorasTotalesProduccion(), 2);
                }
            }
            else {
                CostesProduccion.CostesVariables = ((DespachoProfesional.CostesDirectos + DespachoProfesional.TasaCostesIndirectos) * (CostesProduccion.porcentaje/100)).DosDecimales();
            }
            CostesProduccion.TotalCostesVariables = CalcularCostesTotales();
            CostesProduccion.TotalCostes = (DespachoProfesional.CostesDirectos + DespachoProfesional.TasaCostesIndirectos + CostesProduccion.CostesVariables).DosDecimales();
            CostesProduccion.CosteHoraExternalizacion = Math.Round(CostesProduccion.TotalCostes * (1 + CostesProduccion.CoeficienteCostesExternalizacion/100),2,MidpointRounding.AwayFromZero);

            //H
            CostesProduccion.HorasProduccionDespachoElabDocumentacion = Math.Round(DespachoProfesional.HorasTotalesProduccion * CostesProduccion.PlazoPresentacionDocumentos / 12, 2, MidpointRounding.AwayFromZero);

            // probar que esto funcione 
            if(CostesProduccion.HorasProduccionDespachoElabDocumentacion > TrabajoProfesional.HorasTPEDocumentacion)
            {
                CostesProduccion.HorasProduccionDespachoElabDocumentacion = TrabajoProfesional.HorasTPEDocumentacion;
            }
            
            CostesProduccion.NumHorasMinimoExt = (CostesProduccion.HorasProduccionDespachoElabDocumentacion >= TrabajoProfesional.HorasTPEDocumentacion) ?
                0 :
                Math.Round(TrabajoProfesional.HorasTPEDocumentacion - CostesProduccion.HorasProduccionDespachoElabDocumentacion,2,MidpointRounding.AwayFromZero);

            //€
            CostesProduccion.IncrementoUrgencia = CalcularIncremento();

            if (CostesProduccion.IncrementoUrgencia == 0)
            {
                if (CostesProduccion.NumHorasMinimoExt == 0)
                {
                    CostesProduccion.CostesProduccionTrabProf = (TrabajoProfesional.HorasTPE * CostesProduccion.TotalCostes).DosDecimales();
                }
                else {
                    CostesProduccion.CostesProduccionTrabProf = (
                        (
                        (CostesProduccion.HorasProduccionDespachoElabDocumentacion + TrabajoProfesional.HorasTPEDireccion)
                        * CostesProduccion.TotalCostes)
                        + (CostesProduccion.NumHorasMinimoExt * CostesProduccion.CosteHoraExternalizacion)
                        ).DosDecimales();
                }
            }
            else {
                var incr = 1+(CostesProduccion.IncrementoUrgencia / 100);
                CostesProduccion.CostesProduccionTrabProf =(
                    (CostesProduccion.HorasProduccionDespachoElabDocumentacion * CostesProduccion.TotalCostes * incr) +
                    (CostesProduccion.CosteHoraExternalizacion * CostesProduccion.NumHorasMinimoExt * incr) +
                    (TrabajoProfesional.HorasTPEDireccion * CostesProduccion.TotalCostes)
                    ).DosDecimales();
            }
                //CostesProduccion.CostesProduccionTrabProf = (CostesProduccion.NumHorasMinimoExt == 0) ?
                //    (TrabajoProfesional.HorasTPE * CostesProduccion.TotalCostes).DosDecimales() :
                //    (((CostesProduccion.HorasProduccionDespachoElabDocumentacion + TrabajoProfesional.HorasTPEDireccion) * CostesProduccion.TotalCostes) + (CostesProduccion.NumHorasMinimoExt * CostesProduccion.CosteHoraExternalizacion)).DosDecimales();
                CostesProduccion.PrecioTrabProf = (CostesProduccion.CostesProduccionTrabProf * (1 + CostesProduccion.Beneficio / 100)).DosDecimales();
            CostesProduccion.TotalOtrosTrabajos = CalcularTotalOtrosTrabajos();
            CostesProduccion.PrecioDelEncargo = (CostesProduccion.PrecioTrabProf + CostesProduccion.TotalOtrosTrabajos).DosDecimales();
        }

 
        #endregion

        /// <summary>
        /// DESPACHO PROFESIONAL
        /// </summary>
        public class CASADespachoProfesional
        {

            public List<Trabajador> Trabajadores { get; set; } = new List<Trabajador>();
            public List<CosteIndirecto> CostesIndirectos { get; set; } = new List<CosteIndirecto>();
            public CostesPersonal CostesPersonal { get; set; } = new CostesPersonal();

            public double HorasTotalesProduccion = 0;
            public double CostesDirectosAnuales = 0;
            public double TotalCostesIndirectos = 0;

            public double CostesDirectos = 0;
            public double TasaCostesIndirectos = 0;
            public double CosteHoraDespachoProfesional = 0;

        }
        public class Trabajador
        {
            public int IdTrabajador = 0;
            public string Nombre { get; set; } = "";
            public double CosteAnual { get; set; } = 0;
            public double JornadaLaboral { get; set; } = 0;
            public double PorcentajeProduccion { get; set; } = 0;
            public double NumTrabajadores { get; set; } = 0;
            public double CosteAnualTotal { get; set; } = 0;
            public double HorasProduccion { get; set; } = 0;
        }
        public class CosteIndirecto
        {
            public int idCosteIndirecto { get; set; } = 0;
            public string Concepto { get; set; } = "";
            //private double _importe = 0;
            //public double importe {
            //    get { return _importe; }
            //    set { 
            //        _importe = value;
            //        coste = _importe * valorPeriodo; 
            //    } }
            public double importe { get; set; } = 0;
            public int idPeriodicidad { get; set; } = 0;
            public double valorPeriodo { get; set; } = 0;
            public int idPuntoInformacion { get; set; } = 0;
            public double coste { get; set; } = 0;
        }
        public class CostesPersonal
        {
            public string Municpio { get; set; } = "41091";
            public int anyo { get; set; } = 2025;

            public List<GrupoTrabajador> GrupoTrabajadores { get; set; } = new List<GrupoTrabajador>();

           
        }
        public class GrupoTrabajador
        {
            public string DenominacionGrupo { get; set; } = "";
            public int idCategoriaProfesional { get; set; } = 0;

            public double TotalDevengado { get; set; } = 0;
            public double Complementos { get; set; } = 0;
            public double segSocialEmpresa { get; set; } = 0;

            public double numPagasAnuales { get; set; } = 0;
            public int HorasJornadaLaboral { get; set; } = 0;

            public double CosteAnualIndividual { get; set; } = 0;

            public int HorasAnuales { get; set; } = 0;

            public double PorcentajeProduccion { get; set; } = 0;

            public double PorcentajeAdministración { get; set; } = 0;

            public double HorasProduccion { get; set; } = 0;
        }

        /// <summary>
        /// Usos Tipologia
        /// </summary>
        /// 
        public class CASATrabajoProfesional
        {
            public CASATrabajoProfesional() { }

            public bool EsPorUsos { get; set; } = true;
            public double Tiempo = 0;
            public List<UsosTipologia> Usos { get; set; } = new List<UsosTipologia>();
            public List<CoeficientesCorrectores> FactoresComplejidad { get; set; } = new List<CoeficientesCorrectores>() { };
            public List<CoeficientesCorrectores> FactoresRendimiento { get; set; } = new List<CoeficientesCorrectores>() { };
            public List<FasesTrabajo> FasesTrabajo { get; set; } = new List<FasesTrabajo>() { };

            public double TotalHorasTPE { get; set; } = 0;
            public double HorasTPE { get; set; } = 0;
            public double HorasTPEDocumentacion { get; set; } = 0;
            public double HorasTPEDireccion { get; set; } = 0;


            public double HorasTPEEstimacion { get; set; } = 0;
            public double HorasTPEDocumentacionEstimacion { get; set; } = 0;
            public double HorasTPEDireccionEstimacion { get; set; } = 0;
        }
        public class UsosTipologia
        {
            public double superficie { get; set; } = 0;
            public int idGrupoTipologia { get; set; } = 0;
            public int idTipologia { get; set; } = 0;
            public int idTipoIntervencion { get; set; } = 0;
            public double CoefTipologia { get; set; } = 0;
            public double SuperficieCoefTipologia { get; set; } = 0;
            public double CoefIntervencion { get; set; } = 0;
            public double SuperficieCoefIntervencion { get; set; } = 0;
        }
        public class CoeficientesCorrectores
        {
            public int idTipoFactor { get; set; } = 0;
            public string Nombre { get; set; } = "";
            public int idCorrecion { get; set; } = 0;
            public double coeficiente { get; set; } = 0;
            public int idPuntoInformacion { get; set; } = 0;
        }
        public class FasesTrabajo
        {
            public int idFase { get; set; } = 0;
            public string Codigo { get; set; } = "";
            public string Denominacion { get; set; } = "";
            public double Porcentaje { get; set; } = 0;
            public double? PlazoMinimo { get; set; } = 0;
            public bool Seleccionado { get; set; } = true;
        }


        /// <summary>
        /// Costes Produccion
        /// </summary>
        public class CASACostesProduccion
        {
            //€/h
            public double CostesVariables { get; set; } = 0;
            public double TotalCostesVariables { get; set; } =0;
            public double TotalCostes { get; set; } = 0;
            public double CoeficienteCostesExternalizacion { get; set; } = 15;
            public double CosteHoraExternalizacion { get; set; } = 0;
            public bool EsCalculado { get; set; } = true;
            public double porcentaje { get; set; } = 3.5;
            public List<CosteVariable> ListaCostesVariables { get; set; } = new List<CosteVariable>();

            //h
            public double PlazoPresentacionDocumentos { get; set; } = 4;
            public double HorasProduccionDespachoElabDocumentacion { get; set; } = 0;
            public double NumHorasMinimoExt { get; set; } = 0;


            //€
            public double CostesProduccionTrabProf { get; set; } = 0;
            public double Beneficio { get; set; } = 0;
            public double PrecioTrabProf { get; set; } = 0;

            public double IncrementoUrgencia { get; set; } = 0;

            public List<OtrosTrabajos> OtrosTrabajos { get; set; } = new List<OtrosTrabajos>();
            public double TotalOtrosTrabajos { get; set; } = 0;
            public double PrecioDelEncargo { get; set; } = 0;

        }
        public class CosteVariable
        {
            public int idCoste { get; set; } = 0;
            public string Denominacion { get; set; } = "";
            public double Coste { get; set; } = 0;
        }
        public class OtrosTrabajos
        {
            public int idTrabajo { get; set; } = 0;
            public string Denominacion { get; set; } = "";
            public double Coste { get; set; } = 0;
        }

        public List<enumeracionesCASA> ListaEnumeracionCASA(List<enumeraciones> lista)
        {

            List<enumeracionesCASA> lu = new List<enumeracionesCASA>();
            foreach (enumeraciones enu in lista.OrderBy(x=>x.Orden)) {
                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,
                idPuntoInformacion = string.IsNullOrEmpty( enu.ValorAlfabetico4) ? null : int.Parse(enu.ValorAlfabetico4),
                ValorNumerico1 = enu.ValorNumerico1
            };
        }
        public class enumeracionesCASA
        {
            public int idEnumeracion { get; set; }

            public int? idGrupoEnumeracion { get; set; }

            public string Codigo { get; set; } = null!;

            public string Descripcion { get; set; } = null!;

            public string? ValorAlfabetico1 { get; set; }

            public string? ValorAlfabetico2 { get; set; }
            public int? idPuntoInformacion { get; set; }
            public double? ValorNumerico1 { get; set; }

            public bool Seleccionado { get; set; } = false!;
        }

        public List<factorescorreccionCASA> ListaFactoresCorreccionCASA(List<factorescorreccion> lista)
        {

            List<factorescorreccionCASA> lu = new List<factorescorreccionCASA>();
            foreach (factorescorreccion enu in lista)
            {
                lu.Add(factorescorreccionACASA(enu));
            }
            return lu;
        }
        public factorescorreccionCASA factorescorreccionACASA(factorescorreccion enu)
        {
            return new factorescorreccionCASA()
            {
                idEnumeracion = enu.idEnumeracion,
                idFactorCorreccion = enu.idFactorCorreccion,
                Descripcion = enu.Descripcion,
                Coeficiente = enu.Coeficiente
            };
        }
        public class factorescorreccionCASA
        {
            public int idFactorCorreccion { get; set; }

            public int idEnumeracion { get; set; }

            public string Descripcion { get; set; } = null!;

            public double Coeficiente { get; set; }
        }

        public List<conveniocolectivoCASA> ListaConvColectivoCASA(List<conveniocolectivo> lista)
        {

            List<conveniocolectivoCASA> lu = new List<conveniocolectivoCASA>();
            foreach (conveniocolectivo enu in lista)
            {
                lu.Add(conColectivoACASA(enu));
            }
            return lu;
        }
        public conveniocolectivoCASA conColectivoACASA(conveniocolectivo enu)
        {
            return new conveniocolectivoCASA()
            {
                idEnumeracion = enu.idEnumeracion,
                idConvenioColectivo = enu.idConvenioColectivo,
                idMunicipio = enu.idProvincia,
                Convenio = (enu.SalarioBase.HasValue ? (double)enu.SalarioBase:0),
                OtrosCostes= (enu.OtrosCostes.HasValue ? (double)enu.OtrosCostes : 0)
            };
        }
        public class conveniocolectivoCASA
        {
            public int idConvenioColectivo { get; set; }

            public int idEnumeracion { get; set; }

            public string idMunicipio { get; set; } = null!;

            public double Convenio { get; set; }

            public double OtrosCostes { get; set; }
        }

        public List<tipologiasCASA> ListaTipologiasCASA(List<tipologias> lista)
        {

            List<tipologiasCASA> lu = new List<tipologiasCASA>();
            foreach (tipologias enu in lista)
            {
                lu.Add(tipologiaACASA(enu));
            }
            return lu;
        }
        public tipologiasCASA tipologiaACASA(tipologias enu)
        {
            return new tipologiasCASA()
            {
                idTipologia = enu.idtipologia,
                idGrupoTip = enu.idGrupoTip,
                Descripcion = enu.Descripcion,
                CoeficienteUso = enu.CoeficienteUso
            };
        }
        public class tipologiasCASA
        {
            public int idTipologia { get; set; }

            public int idGrupoTip { get; set; }

            public string Descripcion { get; set; } = null!;

            public double CoeficienteUso { get; set; }
        }

    }
}
