using app_datafono_difare.Entities;
using app_datafono_difare.Helpers;
using ClsRgFunciones;
using com.sun.xml.@internal.ws.util.xml;
using Newtonsoft.Json;
using org.omg.CosNaming;
using Serilog;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
using System.Xml;
using static app_datafono_difare.Program;

namespace app_datafono_difare.Services
{
        public class TransactionService
        {
            private readonly RgService _rg;
            private readonly string _rutaBines;

        public TransactionService(RgService rgService, string rutaBines)
            {
                _rg = rgService;
                _rutaBines = rutaBines;
            }

            public async Task<TransaccionResponse> ProcesarVenta(string url, string estacion, decimal monto, int cuotas)
            {
                Log.Information("Configurando servicio...");
     
                _rg.Rg.EstablecerServicio(url);
                _rg.Rg.EstablecerEstacion(estacion);
                _rg.Rg.ConfigurarTerminal(estacion);
                _rg.Rg.ConfigurarPinpad();

                Log.Information("Datos configurados. Ejecutando venta...");
                return await EnviarVenta(monto, cuotas);
            }

            public async Task<TransaccionResponse> EnviarVenta(decimal monto, int cuotas)
            {
             
                    string codigo = string.Empty;
                    int numeroCuotas = cuotas;

                    bool tieneCuotas = numeroCuotas > 0;

                    string tipoTran = tieneCuotas ? "02" : "01";
                    string tipoCompra = tieneCuotas ? "02" : "00";
                    string cuotaStr = numeroCuotas.ToString("00");

                    int montoTotal = (int)(monto * 100);
                    string montoTotalStr = montoTotal.ToString();

                    int base12 = (int)(monto * 100 / 1.12m);
                    int iva = montoTotal - base12;

                    string base12Str = base12.ToString();
                    string base0Str = "0";
                    string ivaStr = iva.ToString();
                    string servicioStr = "0";
                    string propinaStr = "0";
                    string secuenciaStr = "0";

                    string aprobacion = "";
                    string fechaAnul = "";
                    string horaAnul = "";
                    string respuesta = "";

                    try
                    {
                    //TODO - Delay para que la DLL funcione correctamente
                    Log.Information("Esperando inicialización de la pinpad...");
                    await Task.Delay(1000);

                    Log.Information("Preparando venta...");
                    await Task.Delay(1000);

                    Log.Information("Enviando comando AUTORIZAR...");

                    // Delay justo antes del comando crítico
                    await Task.Delay(1500);
                     //Parsear valores
                string resultado = _rg.Rg.Autorizar(
                        ref codigo,
                        int.Parse(tipoTran),
                        int.Parse(tipoCompra),
                        int.Parse(cuotaStr),
                        double.Parse(montoTotalStr) / 100.0,
                        double.Parse(base12Str) / 100.0,
                        double.Parse(base0Str) / 100.0,
                        double.Parse(ivaStr) / 100.0,
                        double.Parse(servicioStr) / 100.0,
                        double.Parse(propinaStr) / 100.0,
                        int.Parse(secuenciaStr),
                        aprobacion,
                        ref fechaAnul,
                        ref horaAnul,
                        ref respuesta
                    );

                        Log.Information("Respuesta cruda: " + resultado);

                        if (resultado.IndexOf("FALLO", StringComparison.OrdinalIgnoreCase) >= 0 ||
                      resultado.IndexOf("CONNECTION", StringComparison.OrdinalIgnoreCase) >= 0)
                        {
                            Log.Error("ERROR DE CONEXIÓN: La pinpad o el servicio remoto no respondió correctamente. Respuesta: " + respuesta);
                            return new TransaccionResponse
                            {
                                ResponseCode = "99",
                                ResponseCodeDescriptor = "ERROR DE CONEXIÓN",
                            }; ;
                        }

                        var response = ProcesarRespuesta(resultado, monto);
                        Log.Information($"Transacción procesada: {response.ResponseCodeDescriptor}");

                return response;

                    }
                    catch (Exception ex)
                    {
                        Log.Error(ex, "Error de validación o error en Autorizar");
                        throw;
                    }
                    
                
            }


        private TransaccionResponse ProcesarRespuesta(string respuesta, decimal amount)
            {

            string iCodigo = string.Empty;
            string iCodigoRed = string.Empty;
            string iCodRespuesta = string.Empty;
            string iMensaje = string.Empty;
            string iReferencia = string.Empty;
            string iLote = string.Empty;
            string iHora = string.Empty;
            string iFecha = string.Empty;
            string iAutorizacion = string.Empty;
            string iTerminal = string.Empty;
            string iComercio = string.Empty;
            string iInteres = string.Empty;
            string iPromocion = string.Empty;
            string iCodAdq = string.Empty;
            string iAdq = string.Empty;
            string iMarca = string.Empty;
            string iModo = string.Empty;
            string iNombre = string.Empty;
            string iMontoFijo = string.Empty;
            string iEmv = string.Empty;
            string iEmv2 = string.Empty;
            string iEmv3 = string.Empty;
            string iPin = string.Empty;
            string iArqc = string.Empty;
            string iTarjeta = string.Empty;
            string iFecVen = string.Empty;
            string iTrack = string.Empty;
            string iRespuesta = string.Empty;
            string iMid2 = string.Empty;

            double dInteres = 0;
            double dMontoFijo = 0;

            ProcesarRespuestaDll(
            respuesta,
            ref iCodigo,
            ref iCodigoRed,
            ref iCodRespuesta,
            ref iMensaje,
            ref iReferencia,
            ref iLote,
            ref iHora,
            ref iFecha,
            ref iAutorizacion,
            ref iTerminal,
            ref iComercio,
            ref iInteres,
            ref iPromocion,
            ref iCodAdq,
            ref iAdq,
            ref iMarca,
            ref iModo,
            ref iNombre,
            ref iMontoFijo,
            ref iEmv,
            ref iEmv2,
            ref iEmv3,
            ref iPin,
            ref iArqc,
            ref iTarjeta,
            ref iFecVen,
            ref iTrack,
            ref iRespuesta,
            ref iMid2);


            var response = new TransaccionResponse
            {
                ReferenceNumber = iAutorizacion?.Trim(),
                SequenceNumber = iReferencia?.Trim(),
                MaskedAccountNumber = iTarjeta?.Trim(),
                CardBrand = iMarca?.Trim(),
                ResponseCode = iCodRespuesta?.Trim(),
                ResponseCodeDescriptor = iMensaje?.Trim(),
                Amount = amount,
                Timestamp = DateHelper.ParseDate(iFecha, iHora),
                CommerceCode = iComercio?.Trim(),
                TerminalId = iTerminal?.Trim(),
                RedCode = iCodigoRed?.Trim(),
                Lote = iLote?.Trim(),
                Promotion = iPromocion?.Trim(),
                CodAdquiriente = iCodAdq?.Trim(),
                idAdquiriente = iAdq?.Trim(),
                LineItemType = ObtenerTipoTarjetaHelper.ObtenerTipoTarjetaPorBin(iTarjeta?.Trim(), _rutaBines)
            };

            var json = JsonConvert.SerializeObject(response);
            Log.Information($"Resultado de la transacción: {json}");
            return response;

        }

        public static string ProcesarRespuestaDll(
            string pRespuesta,
            ref string iCodigo,
            ref string iCodigoRed,
            ref string iCodRespuesta,
            ref string iMensaje,
            ref string iReferencia,
            ref string iLote,
            ref string iHora,
            ref string iFecha,
            ref string iAutorizacion,
            ref string iTerminal,
            ref string iComercio,
            ref string iInteres,
            ref string iPromocion,
            ref string iCodAdq,
            ref string iAdq,
            ref string iMarca,
            ref string iModo,
            ref string iNombre,
            ref string iMontoFijo,
            ref string iEmv,
            ref string iEmv2,
            ref string iEmv3,
            ref string iPin,
            ref string iArqc,
            ref string iTarjeta,
            ref string iFecVen,
            ref string iTrack,
            ref string iRespuesta,
            ref string iMid2)
        {


            // Variables con tipos correctos
            double dInteres = 0;
            double dMontoFijo = 0;

            var rg = RgFunciones.Instancia;

            var resultado = rg.ProcesarRespuesta(
                pRespuesta,
                ref iCodigo,
                ref iCodigoRed,
                ref iCodRespuesta,
                ref iMensaje,
                ref iReferencia,
                ref iLote,
                ref iHora,
                ref iFecha,
                ref iAutorizacion,
                ref iTerminal,
                ref iComercio,
                ref dInteres,
                ref iPromocion,
                ref iCodAdq,
                ref iAdq,
                ref iMarca,
                ref iModo,
                ref iNombre,
                ref dMontoFijo,
                ref iEmv,
                ref iEmv2,
                ref iEmv3,
                ref iPin,
                ref iArqc,
                ref iTarjeta,
                ref iFecVen,
                ref iTrack,
                ref iRespuesta,
                ref iMid2);

            // Convertir doubles a strings
            iInteres = dInteres.ToString("F2");
            iMontoFijo = dMontoFijo.ToString("F2");

            return resultado;
        }
    }
}
