using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using QRRapidoApp.Services;
using QRRapidoApp.Models;
using System.Security.Claims;
using System.Threading.Tasks;
using QRRapidoApp.Models.ViewModels;
using System.Linq;
using MongoDB.Driver;
using QRRapidoApp.Data;
using System.Text;
using Stripe.Checkout;

namespace QRRapidoApp.Controllers
{
    [Authorize]
    public class PagamentoController : Controller
    {
        private readonly IUserService _userService;
        private readonly ILogger<PagamentoController> _logger;
        private readonly MongoDbContext _context;
        private readonly AdDisplayService _adDisplayService;
        private readonly StripeService _stripeService; // Injected StripeService
        private readonly string _pixKey = "12048391000101"; 
        private readonly string _merchantName = "RRCG Gerenciamento";
        private readonly string _merchantCity = "SAO PAULO";

        public PagamentoController(
            IUserService userService, 
            ILogger<PagamentoController> logger, 
            MongoDbContext context, 
            AdDisplayService adDisplayService, 
            IConfiguration config,
            StripeService stripeService)
        {
            _userService = userService;
            _logger = logger;
            _context = context;
            _adDisplayService = adDisplayService;
            _stripeService = stripeService;
            
            var configPixKey = config["Payment:PixKey"];
            if (!string.IsNullOrEmpty(configPixKey))
            {
                _pixKey = configPixKey;
            }
        }

        [HttpGet]
        public async Task<IActionResult> SelecaoPlano()
        {
            _adDisplayService.SetViewBagAds(ViewBag);
            
            // Definição dos pacotes com PREÇOS DIFERENCIADOS
            var packages = GetPackages();

            return View(packages);
        }

        [HttpPost("api/Pagamento/CreatePixOrder")]
        public async Task<IActionResult> CreatePixOrder([FromBody] CreateOrderRequest request)
        {
            var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
            var userEmail = User.FindFirst(ClaimTypes.Email)?.Value;

            if (string.IsNullOrEmpty(userId)) return Unauthorized();

            var package = GetPackage(request.PackageId);
            if (package == null) return BadRequest("Pacote inválido");

            try 
            {
                // Create Order (PIX Price)
                var order = new Order
                {
                    UserId = userId,
                    UserEmail = userEmail ?? "unknown",
                    Amount = package.PricePix,
                    CreditsAmount = package.Credits,
                    Status = "Pending",
                    CreatedAt = DateTime.UtcNow
                };

                await _context.Orders.InsertOneAsync(order);

                var shortId = order.Id.Substring(order.Id.Length - 8).ToUpper(); 
                var txId = $"PED{shortId}";
                
                var update = Builders<Order>.Update.Set(o => o.PixCode, txId);
                await _context.Orders.UpdateOneAsync(o => o.Id == order.Id, update);

                var pixPayload = PixPayloadGenerator.GeneratePayload(
                    _pixKey, 
                    package.PricePix, 
                    _merchantName, 
                    _merchantCity, 
                    txId
                );

                return Ok(new 
                { 
                    success = true, 
                    pixCode = pixPayload, 
                    orderId = txId, 
                    amount = package.PricePix,
                    credits = package.Credits
                });
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Erro ao gerar pedido PIX");
                return StatusCode(500, new { success = false, error = "Erro interno" });
            }
        }

        [HttpPost("api/Pagamento/CreateStripeSession")]
        public async Task<IActionResult> CreateStripeSession([FromBody] CreateOrderRequest request)
        {
            var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
            if (string.IsNullOrEmpty(userId)) return Unauthorized();

            var package = GetPackage(request.PackageId);
            if (package == null) return BadRequest("Pacote inválido");

            try
            {
                // Create Stripe Checkout Session (One-Time Payment)
                // We create an ad-hoc price on the fly using line_items
                var options = new SessionCreateOptions
                {
                    PaymentMethodTypes = new List<string> { "card" },
                    Mode = "payment", // One-time payment
                    LineItems = new List<SessionLineItemOptions>
                    {
                        new SessionLineItemOptions
                        {
                            PriceData = new SessionLineItemPriceDataOptions
                            {
                                Currency = "brl",
                                UnitAmount = (long)(package.PriceCard * 100), // Centavos
                                ProductData = new SessionLineItemPriceDataProductDataOptions
                                {
                                    Name = $"{package.Credits} Créditos QR Rapido",
                                    Description = package.Description
                                }
                            },
                            Quantity = 1,
                        },
                    },
                    Metadata = new Dictionary<string, string>
                    {
                        { "user_id", userId },
                        { "credits_amount", package.Credits.ToString() },
                        { "package_id", package.Id }
                    },
                    SuccessUrl = $"{Request.Scheme}://{Request.Host}/Pagamento/Sucesso",
                    CancelUrl = $"{Request.Scheme}://{Request.Host}/Pagamento/SelecaoPlano",
                };

                var service = new SessionService();
                var session = await service.CreateAsync(options);

                return Ok(new { success = true, url = session.Url });
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Stripe session error");
                return StatusCode(500, new { success = false, error = ex.Message });
            }
        }

        private List<CreditPackageViewModel> GetPackages()
        {
            return new List<CreditPackageViewModel>
            {
                new CreditPackageViewModel { 
                    Id = "starter", 
                    Name = "Iniciante", 
                    Credits = 10, 
                    PricePix = 5.00m,  // R$ 0,50/un
                    PriceCard = 6.00m, 
                    Description = "Ideal para testes rápidos", 
                    Savings = 0 
                },
                new CreditPackageViewModel { 
                    Id = "pro", 
                    Name = "Profissional", 
                    Credits = 50, 
                    PricePix = 22.50m, // R$ 0,45/un (Desconto de volume)
                    PriceCard = 27.00m, 
                    Description = "Para uso recorrente", 
                    Savings = 10, 
                    IsPopular = true 
                },
                new CreditPackageViewModel { 
                    Id = "agency", 
                    Name = "Agência", 
                    Credits = 100, 
                    PricePix = 40.00m, // R$ 0,40/un (Super desconto)
                    PriceCard = 48.00m, 
                    Description = "Volume alto com desconto máximo", 
                    Savings = 20 
                }
            };
        }

        private CreditPackageViewModel? GetPackage(string id)
        {
            return GetPackages().FirstOrDefault(p => p.Id == id);
        }

        public class CreateOrderRequest
        {
            public string PackageId { get; set; }
        }

        public class CreditPackageViewModel
        {
            public string Id { get; set; }
            public string Name { get; set; }
            public int Credits { get; set; }
            public decimal PricePix { get; set; }  // Preço PIX
            public decimal PriceCard { get; set; } // Preço Cartão (+taxas)
            public string Description { get; set; }
            public int Savings { get; set; }
            public bool IsPopular { get; set; }
        }

        // --- Helper Interno para Gerar PIX (CRC16) ---
        public static class PixPayloadGenerator
        {
            public static string GeneratePayload(string pixKey, decimal amount, string merchantName, string merchantCity, string txId)
            {
                var sb = new StringBuilder();
                sb.Append(FormatField("00", "01"));
                var merchantInfo = new StringBuilder();
                merchantInfo.Append(FormatField("00", "br.gov.bcb.pix"));
                merchantInfo.Append(FormatField("01", pixKey));
                sb.Append(FormatField("26", merchantInfo.ToString()));
                sb.Append(FormatField("52", "0000"));
                sb.Append(FormatField("53", "986"));
                sb.Append(FormatField("54", amount.ToString("F2", System.Globalization.CultureInfo.InvariantCulture)));
                sb.Append(FormatField("58", "BR"));
                var name = merchantName.Length > 25 ? merchantName.Substring(0, 25) : merchantName;
                sb.Append(FormatField("59", RemoveAccents(name)));
                var city = merchantCity.Length > 15 ? merchantCity.Substring(0, 15) : merchantCity;
                sb.Append(FormatField("60", RemoveAccents(city)));
                var additionalData = new StringBuilder();
                additionalData.Append(FormatField("05", txId)); 
                sb.Append(FormatField("62", additionalData.ToString()));
                sb.Append("6304");
                var payloadWithoutCrc = sb.ToString();
                var crc = CalculateCRC16(payloadWithoutCrc);
                return payloadWithoutCrc + crc;
            }

            private static string FormatField(string id, string value) => $"{id}{value.Length:D2}{value}";

            private static string RemoveAccents(string text)
            {
                return text.ToUpper()
                    .Replace("Ã", "A").Replace("Á", "A").Replace("Â", "A")
                    .Replace("É", "E").Replace("Ê", "E")
                    .Replace("Í", "I")
                    .Replace("Ó", "O").Replace("Ô", "O").Replace("Õ", "O")
                    .Replace("Ú", "U")
                    .Replace("Ç", "C");
            }

            private static string CalculateCRC16(string data)
            {
                ushort crc = 0xFFFF;
                byte[] bytes = Encoding.ASCII.GetBytes(data);
                foreach (byte b in bytes)
                {
                    crc ^= (ushort)(b << 8);
                    for (int i = 0; i < 8; i++)
                    {
                        if ((crc & 0x8000) != 0) crc = (ushort)((crc << 1) ^ 0x1021);
                        else crc <<= 1;
                    }
                }
                return crc.ToString("X4");
            }
        }
    }
}