using Exferia_Aplicacion.General;
using Exferia_KairosPRO_EF;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using static Exferia_Aplicacion.General.Enumerados;

namespace Exferia_KairosPRO._2_Datos
{
    public class USR_Trazabilidad_Datos
    {
        public static void Grabar_Trazabilidad(Type _typ_tipoObjeto, object _obj_modeloViejo, object _obj_modeloNuevo, Enumerados.G_ENUM_TIPOACCION _enum_tipo, KairosProEntities _context)
        {
            try
            {
                DateTime dt_fechaModificacion = DateTime.Now;
                //Obtenemos el tipo de objeto
                Type typ_tipoObjeto = _typ_tipoObjeto;

                IList<PropertyInfo> lst_prop_obj_modeloNuevo = new List<PropertyInfo>(typ_tipoObjeto.GetProperties().Where(n => n.GetMethod.IsVirtual == false));
                IList<PropertyInfo> lst_prop_obj_modeloViejo = null;

                if (_enum_tipo != G_ENUM_TIPOACCION.INT_ELIMINAR)
                {
                    //Listamos las propiedades de los modelos viejo y nuevo filtrando las propiedades relacionales de otras tablas(...)
                    if (_enum_tipo == G_ENUM_TIPOACCION.INT_MODIFICAR)
                    {
                        lst_prop_obj_modeloViejo = new List<PropertyInfo>(typ_tipoObjeto.GetProperties().Where(n => n.GetMethod.IsVirtual == false));
                    }

                    //Recorremos por propiedades
                    for (int i = 0; i < lst_prop_obj_modeloNuevo.Count(); i++)
                    {
                        string str_valorNuevo = lst_prop_obj_modeloNuevo[i].GetValue(_obj_modeloNuevo, null) != null ? lst_prop_obj_modeloNuevo[i].GetValue(_obj_modeloNuevo, null).ToString() : "";
                        string str_valorViejo = "";
                        //Guardamos en string los valores viejo y nuevo
                        if (_enum_tipo == G_ENUM_TIPOACCION.INT_MODIFICAR)
                        {
                            str_valorViejo = lst_prop_obj_modeloViejo[i].GetValue(_obj_modeloViejo, null) != null ? lst_prop_obj_modeloViejo[i].GetValue(_obj_modeloViejo, null).ToString() : "";
                        }

                        //(Si no es modificacion y no está vacio) o (Es modificacion y los campos son distintos) lo grabamos
                        if ((_enum_tipo != G_ENUM_TIPOACCION.INT_MODIFICAR && !string.IsNullOrEmpty(str_valorNuevo)) || !str_valorViejo.Equals(str_valorNuevo))
                        {
                            //Guardamos un registro de trazabilidad
                            USR_Trazabilidad mdl_USR_Trazabilidad = new USR_Trazabilidad();
                            mdl_USR_Trazabilidad.idUsuario = Variables.G_MDL_USUARIOVALIDADO_MODELO.id;
                            mdl_USR_Trazabilidad.codigoCliente = Variables.G_LNG_IDCLIENTE_LICENCIAVALIDADO;
                            mdl_USR_Trazabilidad.campo = lst_prop_obj_modeloNuevo[i].Name;
                            mdl_USR_Trazabilidad.tabla = typ_tipoObjeto.Name;
                            mdl_USR_Trazabilidad.tipoAccion = (int)_enum_tipo;

                            //Si el idModificado es long lo parseamos, si no lo guardamos en un campo string.
                            long lng_idModificado;
                            if (long.TryParse(lst_prop_obj_modeloNuevo[0].GetValue(_obj_modeloNuevo).ToString(), out lng_idModificado))
                            {
                                mdl_USR_Trazabilidad.clave_Modificado = lng_idModificado; //el primer field de los modelos siempre es id
                            }
                            else
                            {
                                mdl_USR_Trazabilidad.clave_Modificado_Texto = lst_prop_obj_modeloNuevo[0].GetValue(_obj_modeloNuevo).ToString();
                            }

                            mdl_USR_Trazabilidad.fechaHora = dt_fechaModificacion;

                            if (_enum_tipo == G_ENUM_TIPOACCION.INT_MODIFICAR)
                            {
                                mdl_USR_Trazabilidad.textoViejo = lst_prop_obj_modeloViejo[i].GetValue(_obj_modeloViejo, null) != null ? lst_prop_obj_modeloViejo[i].GetValue(_obj_modeloViejo, null).ToString() : "";
                            }
                            else
                            {
                                mdl_USR_Trazabilidad.textoViejo = "";
                            }

                            mdl_USR_Trazabilidad.textoNuevo = lst_prop_obj_modeloNuevo[i].GetValue(_obj_modeloNuevo, null) != null ? lst_prop_obj_modeloNuevo[i].GetValue(_obj_modeloNuevo, null).ToString() : null;

                            Grabar_Trazabilidad_Final(mdl_USR_Trazabilidad, typ_tipoObjeto.Name, _context);
                        }
                    }
                }
                else // Si es eliminación solo se crea un registro indicando la tabla y el id eliminado
                {
                    //Guardamos un registro de trazabilidad
                    USR_Trazabilidad mdl_USR_Trazabilidad = new USR_Trazabilidad();
                    mdl_USR_Trazabilidad.idUsuario = Variables.G_MDL_USUARIOVALIDADO_MODELO.id;
                    mdl_USR_Trazabilidad.codigoCliente = Variables.G_LNG_IDCLIENTE_LICENCIAVALIDADO;
                    mdl_USR_Trazabilidad.campo = "";
                    mdl_USR_Trazabilidad.tabla = typ_tipoObjeto.Name;
                    mdl_USR_Trazabilidad.tipoAccion = (int)_enum_tipo;

                    //Si el idModificado es long lo parseamos, si no lo guardamos en un campo string.
                    long lng_idModificado;
                    if (long.TryParse(lst_prop_obj_modeloNuevo[0].GetValue(_obj_modeloNuevo).ToString(), out lng_idModificado))
                    {
                        mdl_USR_Trazabilidad.clave_Modificado = lng_idModificado; //el primer field de los modelos siempre es id
                    }
                    else
                    {
                        mdl_USR_Trazabilidad.clave_Modificado_Texto = lst_prop_obj_modeloNuevo[0].GetValue(_obj_modeloNuevo).ToString();
                    }

                    mdl_USR_Trazabilidad.fechaHora = dt_fechaModificacion;
                    mdl_USR_Trazabilidad.textoViejo = "";
                    mdl_USR_Trazabilidad.textoNuevo = "";

                    Grabar_Trazabilidad_Final(mdl_USR_Trazabilidad, typ_tipoObjeto.Name, _context);
                }
            }
            catch (Exception ex)
            {
                Control_Errores.Errores_Log("", ex, nameof(USR_Trazabilidad_Datos) + "/" + nameof(Grabar_Trazabilidad));
            }
        }
        private static void Grabar_Trazabilidad_Final(USR_Trazabilidad _mdl_USR_Trazabilidad, string _str_ModeloNombre, KairosProEntities _context)
        {
            // Se comprueba que se haya cargado correctamente el modelo de trazabilidad.
            if (!string.IsNullOrEmpty(_mdl_USR_Trazabilidad.tabla))
            {
                try
                {
                    _context.USR_Trazabilidad.Add(_mdl_USR_Trazabilidad);
                    _context.SaveChanges();
                }
                catch (Exception ex)
                {
                    Control_Errores.Errores_Log("", ex, nameof(USR_Trazabilidad_Datos) + "/" + nameof(Grabar_Trazabilidad_Final));
                }
            }
            else
            {
                Control_Errores.Errores_Log("", null, nameof(USR_Trazabilidad_Datos) + "/" + nameof(Grabar_Trazabilidad_Final));
            }
        }
    }
}
