using Microsoft.AspNetCore.Mvc;
using QRRapidoApp.Data;
using QRRapidoApp.Models;
using QRRapidoApp.Services;
using MongoDB.Driver;
using System.Security.Claims;

namespace QRRapidoApp.Controllers
{
    public class AdminController : Controller
    {
        private readonly MongoDbContext _context;
        private readonly ILogger<AdminController> _logger;
        private readonly IConfiguration _config;
        private readonly IUserService _userService;

        public AdminController(MongoDbContext context, ILogger<AdminController> logger, IConfiguration config, IUserService userService)
        {
            _context = context;
            _logger = logger;
            _config = config;
            _userService = userService;
        }

        private bool IsAdmin()
        {
            // 1. Check if authenticated
            if (User?.Identity?.IsAuthenticated != true) return false;

            // 2. Get User Email
            var userEmail = User.FindFirst(ClaimTypes.Email)?.Value;
            if (string.IsNullOrEmpty(userEmail))
            {
                // Fallback: try to find user by ID to get email
                var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
                if (!string.IsNullOrEmpty(userId))
                {
                    var user = _userService.GetUserAsync(userId).Result;
                    userEmail = user?.Email;
                }
            }

            if (string.IsNullOrEmpty(userEmail)) return false;

            // 3. Check against AllowedEmails list
            var allowedEmails = _config.GetSection("Admin:AllowedEmails").Get<List<string>>() ?? new List<string>();
            return allowedEmails.Contains(userEmail, StringComparer.OrdinalIgnoreCase);
        }

        private bool IsLocalhost()
        {
            var remoteIp = HttpContext.Connection.RemoteIpAddress;
            return remoteIp != null &&
                   (remoteIp.ToString() == "127.0.0.1" ||
                    remoteIp.ToString() == "::1" ||
                    remoteIp.ToString() == "localhost");
        }

        // --- View Actions ---

        [HttpGet("/Admin")]
        public async Task<IActionResult> Index()
        {
            if (!IsAdmin()) return RedirectToAction("Index", "Home");

            try
            {
                var orders = await _context.Orders
                    .Find(o => o.Status == "Pending")
                    .SortByDescending(o => o.CreatedAt)
                    .ToListAsync();

                return View(orders);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error fetching pending orders for view");
                return View(new List<Order>());
            }
        }

        // --- API Endpoints ---

        [HttpGet("api/Admin/Orders/Pending")]
        public async Task<IActionResult> GetPendingOrders()
        {
            if (!IsAdmin()) return Unauthorized("Access denied. Admin rights required.");

            try
            {
                var orders = await _context.Orders
                    .Find(o => o.Status == "Pending")
                    .SortByDescending(o => o.CreatedAt)
                    .ToListAsync();

                return Ok(orders);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error fetching pending orders");
                return StatusCode(500, new { error = "Internal server error" });
            }
        }

        [HttpPost("api/Admin/Orders/{orderId}/Approve")]
        public async Task<IActionResult> ApproveOrder(string orderId)
        {
            if (!IsAdmin()) return Unauthorized("Access denied. Admin rights required.");

            try
            {
                var adminEmail = User.FindFirst(ClaimTypes.Email)?.Value ?? "unknown_admin";

                // 1. Get the order
                var order = await _context.Orders
                    .Find(o => o.Id == orderId)
                    .FirstOrDefaultAsync();

                if (order == null) return NotFound("Order not found");
                if (order.Status == "Paid") return BadRequest("Order already paid");

                // 2. Update Order Status
                var updateOrder = Builders<Order>.Update
                    .Set(o => o.Status, "Paid")
                    .Set(o => o.PaidAt, DateTime.UtcNow)
                    .Set(o => o.ApprovedBy, adminEmail);

                await _context.Orders.UpdateOneAsync(o => o.Id == orderId, updateOrder);

                // 3. Add Credits to User
                var userUpdate = Builders<User>.Update.Inc(u => u.Credits, order.CreditsAmount);
                await _context.Users.UpdateOneAsync(u => u.Id == order.UserId, userUpdate);

                _logger.LogInformation($"Order {orderId} approved by {adminEmail}. {order.CreditsAmount} credits added to user {order.UserId}");

                return Ok(new { success = true, message = "Order approved and credits added." });
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"Error approving order {orderId}");
                return StatusCode(500, new { error = "Internal server error" });
            }
        }

        [HttpPost("api/Admin/Orders/{orderId}/Reject")]
        public async Task<IActionResult> RejectOrder(string orderId)
        {
            if (!IsAdmin()) return Unauthorized("Access denied. Admin rights required.");

            try
            {
                var adminEmail = User.FindFirst(ClaimTypes.Email)?.Value ?? "unknown_admin";

                var update = Builders<Order>.Update
                    .Set(o => o.Status, "Rejected")
                    .Set(o => o.ApprovedBy, adminEmail); // Rejected by...

                var result = await _context.Orders.UpdateOneAsync(o => o.Id == orderId, update);

                if (result.ModifiedCount == 0) return NotFound("Order not found");

                _logger.LogInformation($"Order {orderId} rejected by {adminEmail}");

                return Ok(new { success = true, message = "Order rejected." });
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"Error rejecting order {orderId}");
                return StatusCode(500, new { error = "Internal server error" });
            }
        }

        // --- Legacy Localhost-Only Endpoints ---

        [HttpPost("api/Admin/SeedPlans")]
        public async Task<IActionResult> SeedPlans([FromBody] List<Plan> plans)
        {
            if (!IsLocalhost()) return Forbid("Localhost only");

            try
            {
                foreach (var plan in plans)
                {
                    var filter = Builders<Plan>.Filter.Eq(p => p.Interval, plan.Interval);
                    var options = new ReplaceOptions { IsUpsert = true };
                    await _context.Plans.ReplaceOneAsync(filter, plan, options);
                }
                return Ok(new { success = true, message = "Plans seeded" });
            }
            catch (Exception ex)
            {
                return StatusCode(500, new { error = ex.Message });
            }
        }

        [HttpGet("api/Admin/Plans")]
        public async Task<IActionResult> GetPlans()
        {
            if (!IsLocalhost()) return Forbid("Localhost only");
            var plans = await _context.Plans.Find(_ => true).ToListAsync();
            return Ok(new { success = true, plans });
        }

        [HttpDelete("api/Admin/Plans")]
        public async Task<IActionResult> DeleteAllPlans()
        {
            if (!IsLocalhost()) return Forbid("Localhost only");
            await _context.Plans.DeleteManyAsync(_ => true);
            return Ok(new { success = true });
        }
    }
}
