using Microsoft.EntityFrameworkCore;
using System.Reflection;
using Models.Interfaces;
using Domain.Entities;
using Models.Models;

namespace Models.Repositories
{
    public class TicketRepository(PhronCareOperationsHubContext dbConnection) : ITicketRepository
    {
        #region Declaraciones y Constructor
        private readonly PhronCareOperationsHubContext _dbConnection = dbConnection;
        #endregion
        #region Metodos de clase
        public async Task<IEnumerable<ETicket>> GetAllAsync()
        {
            var tickets = await _dbConnection.PhOhTickets.ToListAsync();
            return tickets.Select(ticket => MapEntity<PhOhTicket, ETicket>(ticket));
        }
        public async Task<ETicket> GetByIdAsync(Guid ticketId)
        {
            try
            {
                var ticket = await _dbConnection.PhOhTickets
                    .FirstOrDefaultAsync(t => t.TicketId == ticketId);

                if (ticket == null) return new ETicket();

                var eTicket = MapEntity<PhOhTicket, ETicket>(ticket);
                return eTicket;
            }
            catch (Exception ex)
            {
                throw new Exception($"{MethodBase.GetCurrentMethod()?.Name} Message: {ex.Message}", ex);
            }
        }
        public async Task InsertTicketAsync(ETicket ticket)
        {
            try
            {
                ticket.TicketId = Guid.NewGuid();
                var dataTicket = MapEntity<ETicket, PhOhTicket>(ticket);

                await _dbConnection.PhOhTickets.AddAsync(dataTicket);
                await _dbConnection.SaveChangesAsync();
            }
            catch (DbUpdateException ex)
            {
                throw new Exception($"{MethodBase.GetCurrentMethod()?.Name} Message: {ex.InnerException?.Message}", ex);
            }
            catch (Exception ex)
            {
                throw new Exception($"{MethodBase.GetCurrentMethod()?.Name} Message: {ex.Message}", ex);
            }
        }
        public async Task<IEnumerable<ETickets_GetSummary>> GetSummaryAsync()
        {
            var summaryResults = new List<ETickets_GetSummary>();
            try
            {
                using var command = _dbConnection.Database.GetDbConnection().CreateCommand();
                command.CommandText = "Tickets_GetSummary";
                command.CommandType = System.Data.CommandType.StoredProcedure;
                await _dbConnection.Database.OpenConnectionAsync();
                using (var reader = await command.ExecuteReaderAsync())
                {
                    while (await reader.ReadAsync())
                    {
                        var eSummary = Activator.CreateInstance<ETickets_GetSummary>();
                        foreach (var propertyInfo in typeof(ETickets_GetSummary).GetProperties())
                        {
                            var columnName = propertyInfo.Name;
                            if (!reader.IsDBNull(reader.GetOrdinal(columnName)))
                            {
                                var value = reader.GetValue(reader.GetOrdinal(columnName));
                                propertyInfo.SetValue(eSummary, value);
                            }
                        }
                        summaryResults.Add(eSummary);
                    }
                }
                await _dbConnection.Database.CloseConnectionAsync();
            }
            catch (Exception ex)
            {
                throw new Exception($"{MethodBase.GetCurrentMethod()?.Name} Message: {ex.Message}", ex);
            }
            return summaryResults;
        }
        public async Task<IEnumerable<ETicket_Dashboard>> GetTicketDashboardAsync(string estado, string orden)
        {
            var ticketDashboardResults = new List<ETicket_Dashboard>();
            try
            {
                using var command = _dbConnection.Database.GetDbConnection().CreateCommand();
                command.CommandText = "Tickets_Dashboard";
                command.CommandType = System.Data.CommandType.StoredProcedure;

                // Agregar parámetros
                var estadoParam = command.CreateParameter();
                estadoParam.ParameterName = "@EstadoParam";
                estadoParam.Value = estado;
                command.Parameters.Add(estadoParam);

                var ordenParam = command.CreateParameter();
                ordenParam.ParameterName = "@OrdenParam";
                ordenParam.Value = orden;
                command.Parameters.Add(ordenParam);

                await _dbConnection.Database.OpenConnectionAsync();
                using (var reader = await command.ExecuteReaderAsync())
                {
                    while (await reader.ReadAsync())
                    {
                        // Crear instancia del resultado usando reflexión
                        var eTicketDashboard = Activator.CreateInstance<ETicket_Dashboard>();
                        foreach (var propertyInfo in typeof(ETicket_Dashboard).GetProperties())
                        {
                            var columnName = propertyInfo.Name;
                            if (!reader.IsDBNull(reader.GetOrdinal(columnName)))
                            {
                                var value = reader.GetValue(reader.GetOrdinal(columnName));
                                propertyInfo.SetValue(eTicketDashboard, value);
                            }
                        }
                        ticketDashboardResults.Add(eTicketDashboard);
                    }
                }
                await _dbConnection.Database.CloseConnectionAsync();
            }
            catch (Exception ex)
            {
                throw new Exception($"{MethodBase.GetCurrentMethod()?.Name} Message: {ex.Message}", ex);
            }
            return ticketDashboardResults;
        }
        #endregion
        #region Métodos Auxiliares
        private static TDestination MapEntity<TSource, TDestination>(TSource source) where TDestination : new()
        {
            var destination = new TDestination();
            foreach (var propertyInfo in typeof(TSource).GetProperties())
            {
                var value = propertyInfo.GetValue(source);
                typeof(TDestination).GetProperty(propertyInfo.Name)?.SetValue(destination, value);
            }
            return destination;
        }
        #endregion
    }
}
