using System;
using System.Data;
using System.Threading.Tasks;
using foundation_system.Data;
using foundation_system.Models.ViewModels.Reportes;
using Microsoft.EntityFrameworkCore;

namespace foundation_system.Services
{
    public class ReporteService : IReporteService
    {
        private readonly ApplicationDbContext _context;

        public ReporteService(ApplicationDbContext context)
        {
            _context = context;
        }

        public async Task<ReporteArqueoViewModel> ObtenerArqueoCajaAsync(DateOnly fecha)
        {
            var vm = new ReporteArqueoViewModel
            {
                Fecha = fecha,
                FechaGeneracion = DateTime.Now,
                GeneradoPor = "Sistema" // En un escenario real, inyectar IHttpContextAccessor para obtener el usuario
            };

            var connection = _context.Database.GetDbConnection();
            bool wasOpen = connection.State == ConnectionState.Open;
            if (!wasOpen)
                await connection.OpenAsync();

            try
            {
                using (var command = connection.CreateCommand())
                {
                    command.CommandText = "SELECT * FROM sp_reporte_arqueo_caja(@p_fecha)";
                    
                    var param = command.CreateParameter();
                    param.ParameterName = "@p_fecha";
                    param.Value = fecha.ToDateTime(TimeOnly.MinValue);
                    param.DbType = DbType.Date;
                    command.Parameters.Add(param);

                    using (var reader = await command.ExecuteReaderAsync())
                    {
                        if (await reader.ReadAsync())
                        {
                            vm.SaldoInicial = reader.GetDecimal(reader.GetOrdinal("saldo_inicial"));
                            vm.TotalIngresos = reader.GetDecimal(reader.GetOrdinal("total_ingresos"));
                            vm.TotalEgresos = reader.GetDecimal(reader.GetOrdinal("total_egresos"));
                            vm.SaldoFinalTeorico = reader.GetDecimal(reader.GetOrdinal("saldo_final_teorico"));
                            vm.IngresosEfectivo = reader.GetDecimal(reader.GetOrdinal("ingresos_efectivo"));
                            vm.IngresosCheque = reader.GetDecimal(reader.GetOrdinal("ingresos_cheque"));
                            vm.IngresosTransferencia = reader.GetDecimal(reader.GetOrdinal("ingresos_transferencia"));
                        }
                    }
                }
            }
            finally
            {
                if (!wasOpen)
                    await connection.CloseAsync();
            }

            return vm;
        }

        public async Task<ReporteMovimientosViewModel> ObtenerMovimientosAsync(DateOnly inicio, DateOnly fin)
        {
            var vm = new ReporteMovimientosViewModel
            {
                FechaInicio = inicio,
                FechaFin = fin,
                FechaGeneracion = DateTime.Now,
                GeneradoPor = "Sistema"
            };

            var connection = _context.Database.GetDbConnection();
            bool wasOpen = connection.State == ConnectionState.Open;
            if (!wasOpen) await connection.OpenAsync();

            try
            {
                using (var command = connection.CreateCommand())
                {
                    command.CommandText = "SELECT * FROM sp_reporte_movimientos(@p_inicio, @p_fin)";
                    AddDateParams(command, inicio, fin);

                    using (var reader = await command.ExecuteReaderAsync())
                    {
                        while (await reader.ReadAsync())
                        {
                            var item = new MovimientoDetalleItem
                            {
                                Id = reader.GetInt64(reader.GetOrdinal("id")),
                                Fecha = DateOnly.FromDateTime(reader.GetDateTime(reader.GetOrdinal("fecha"))),
                                Tipo = reader.GetString(reader.GetOrdinal("tipo_movimiento")),
                                Concepto = reader.GetString(reader.GetOrdinal("concepto")),
                                Categoria = reader.GetString(reader.GetOrdinal("categoria")),
                                Monto = reader.GetDecimal(reader.GetOrdinal("monto")),
                                Usuario = reader.GetString(reader.GetOrdinal("usuario"))
                            };
                            vm.Movimientos.Add(item);
                            
                            if (item.Tipo == "INGRESO" || item.Tipo == "APERTURA" || item.Tipo == "REPOSICION" || item.Tipo == "AUMENTO_FONDO")
                                vm.TotalIngresos += item.Monto;
                            else
                                vm.TotalEgresos += item.Monto;
                        }
                    }
                }
            }
            finally
            {
                if (!wasOpen) await connection.CloseAsync();
            }
            return vm;
        }

        public async Task<ReporteHistoricoSaldosViewModel> ObtenerHistoricoSaldosAsync(DateOnly inicio, DateOnly fin)
        {
            var vm = new ReporteHistoricoSaldosViewModel
            {
                FechaInicio = inicio,
                FechaFin = fin,
                FechaGeneracion = DateTime.Now,
                GeneradoPor = "Sistema"
            };

            var connection = _context.Database.GetDbConnection();
            bool wasOpen = connection.State == ConnectionState.Open;
            if (!wasOpen) await connection.OpenAsync();

            try
            {
                using (var command = connection.CreateCommand())
                {
                    command.CommandText = "SELECT * FROM sp_reporte_historico_saldos(@p_inicio, @p_fin)";
                    AddDateParams(command, inicio, fin);

                    using (var reader = await command.ExecuteReaderAsync())
                    {
                        while (await reader.ReadAsync())
                        {
                            vm.Saldos.Add(new SaldoDiarioItem
                            {
                                Fecha = DateOnly.FromDateTime(reader.GetDateTime(reader.GetOrdinal("fecha"))),
                                SaldoInicial = reader.GetDecimal(reader.GetOrdinal("saldo_inicial")),
                                Ingresos = reader.GetDecimal(reader.GetOrdinal("ingresos")),
                                Egresos = reader.GetDecimal(reader.GetOrdinal("egresos")),
                                SaldoFinal = reader.GetDecimal(reader.GetOrdinal("saldo_final"))
                            });
                        }
                    }
                }
            }
            finally
            {
                if (!wasOpen) await connection.CloseAsync();
            }
            return vm;
        }

        public async Task<ReporteGastosCategoriaViewModel> ObtenerGastosCategoriaAsync(DateOnly inicio, DateOnly fin)
        {
            var vm = new ReporteGastosCategoriaViewModel
            {
                FechaInicio = inicio,
                FechaFin = fin,
                FechaGeneracion = DateTime.Now,
                GeneradoPor = "Sistema"
            };

            var connection = _context.Database.GetDbConnection();
            bool wasOpen = connection.State == ConnectionState.Open;
            if (!wasOpen) await connection.OpenAsync();

            try
            {
                using (var command = connection.CreateCommand())
                {
                    command.CommandText = "SELECT * FROM sp_reporte_gastos_categoria(@p_inicio, @p_fin)";
                    AddDateParams(command, inicio, fin);

                    using (var reader = await command.ExecuteReaderAsync())
                    {
                        while (await reader.ReadAsync())
                        {
                            var item = new GastoCategoriaItem
                            {
                                Categoria = reader.GetString(reader.GetOrdinal("categoria")),
                                CantidadTransacciones = reader.GetInt32(reader.GetOrdinal("cantidad")),
                                MontoTotal = reader.GetDecimal(reader.GetOrdinal("monto_total"))
                            };
                            vm.Categorias.Add(item);
                            vm.TotalGastos += item.MontoTotal;
                        }
                    }
                }
                
                // Calculate percentages
                if (vm.TotalGastos > 0)
                {
                    foreach (var cat in vm.Categorias)
                    {
                        cat.Porcentaje = (cat.MontoTotal / vm.TotalGastos) * 100;
                    }
                }
            }
            finally
            {
                if (!wasOpen) await connection.CloseAsync();
            }
            return vm;
        }

        public async Task<ReporteReposicionesViewModel> ObtenerReposicionesAsync(DateOnly inicio, DateOnly fin)
        {
            var vm = new ReporteReposicionesViewModel
            {
                FechaInicio = inicio,
                FechaFin = fin,
                FechaGeneracion = DateTime.Now,
                GeneradoPor = "Sistema"
            };

            var connection = _context.Database.GetDbConnection();
            bool wasOpen = connection.State == ConnectionState.Open;
            if (!wasOpen) await connection.OpenAsync();

            try
            {
                using (var command = connection.CreateCommand())
                {
                    command.CommandText = "SELECT * FROM sp_reporte_reposiciones(@p_inicio, @p_fin)";
                    AddDateParams(command, inicio, fin);

                    using (var reader = await command.ExecuteReaderAsync())
                    {
                        while (await reader.ReadAsync())
                        {
                            var item = new ReposicionItem
                            {
                                Fecha = DateOnly.FromDateTime(reader.GetDateTime(reader.GetOrdinal("fecha"))),
                                Monto = reader.GetDecimal(reader.GetOrdinal("monto")),
                                Usuario = reader.GetString(reader.GetOrdinal("usuario")),
                                Descripcion = reader.GetString(reader.GetOrdinal("descripcion"))
                            };
                            vm.Reposiciones.Add(item);
                            vm.TotalRepuesto += item.Monto;
                        }
                    }
                }
            }
            finally
            {
                if (!wasOpen) await connection.CloseAsync();
            }
            return vm;
        }

        private void AddDateParams(System.Data.Common.DbCommand command, DateOnly inicio, DateOnly fin)
        {
            var p1 = command.CreateParameter();
            p1.ParameterName = "@p_inicio";
            p1.Value = inicio.ToDateTime(TimeOnly.MinValue);
            p1.DbType = DbType.Date;
            command.Parameters.Add(p1);

            var p2 = command.CreateParameter();
            p2.ParameterName = "@p_fin";
            p2.Value = fin.ToDateTime(TimeOnly.MaxValue);
            p2.DbType = DbType.Date;
            command.Parameters.Add(p2);
        }
    }
}