using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using LittleShop.Services;
using LittleShop.DTOs;
using LittleShop.Enums;

namespace LittleShop.Controllers;

[ApiController]
[Route("api/[controller]")]
[Authorize(AuthenticationSchemes = "Bearer")]
public class ShippingController : ControllerBase
{
    private readonly IRoyalMailService _royalMailService;
    private readonly IShippingRateService _shippingRateService;
    private readonly IOrderService _orderService;
    private readonly ILogger<ShippingController> _logger;

    public ShippingController(
        IRoyalMailService royalMailService,
        IShippingRateService shippingRateService,
        IOrderService orderService,
        ILogger<ShippingController> logger)
    {
        _royalMailService = royalMailService;
        _shippingRateService = shippingRateService;
        _orderService = orderService;
        _logger = logger;
    }

    [HttpPost("calculate")]
    [AllowAnonymous]
    public async Task<ActionResult<ShippingCalculationResult>> CalculateShipping([FromBody] CalculateShippingRequest request)
    {
        try
        {
            // First try Royal Mail services
            var services = await _royalMailService.GetAvailableServicesAsync(request.WeightInGrams, request.Country);
            
            if (services.Any())
            {
                var result = new ShippingCalculationResult
                {
                    Success = true,
                    Services = services.Select(s => new ShippingOption
                    {
                        ServiceCode = s.Code,
                        ServiceName = s.Name,
                        Description = s.Description,
                        Cost = s.Price,
                        EstimatedDeliveryDays = s.EstimatedDeliveryDays,
                        SupportsTracking = s.SupportsTracking
                    }).ToList()
                };

                return Ok(result);
            }

            // Fallback to local shipping rates
            var fallbackRate = await _shippingRateService.CalculateShippingAsync(request.WeightInGrams / 1000, request.Country);
            if (fallbackRate != null)
            {
                var fallbackResult = new ShippingCalculationResult
                {
                    Success = true,
                    Services = new List<ShippingOption>
                    {
                        new ShippingOption
                        {
                            ServiceCode = "Standard",
                            ServiceName = fallbackRate.Name,
                            Description = fallbackRate.Description ?? "Standard shipping",
                            Cost = fallbackRate.Price,
                            EstimatedDeliveryDays = (fallbackRate.MinDeliveryDays + fallbackRate.MaxDeliveryDays) / 2,
                            SupportsTracking = false
                        }
                    }
                };

                return Ok(fallbackResult);
            }

            return BadRequest(new { Error = "No shipping options available for this destination" });
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error calculating shipping for weight {Weight}g to {Country}", 
                request.WeightInGrams, request.Country);
            return StatusCode(500, new { Error = "Error calculating shipping costs" });
        }
    }

    [HttpPost("create")]
    [Authorize(Roles = "Admin")]
    public async Task<ActionResult<CreateShipmentResult>> CreateShipment([FromBody] CreateShipmentRequest request)
    {
        try
        {
            var result = await _royalMailService.CreateShipmentAsync(request);
            
            if (result.Success)
            {
                _logger.LogInformation("Created shipment {ShipmentId} with tracking {TrackingNumber}", 
                    result.ShipmentId, result.TrackingNumber);
                return Ok(result);
            }
            else
            {
                return BadRequest(new { Error = result.ErrorMessage });
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error creating shipment");
            return StatusCode(500, new { Error = "Error creating shipment" });
        }
    }

    [HttpPost("orders/{orderId}/ship")]
    [Authorize(Roles = "Admin")]
    public async Task<ActionResult<CreateShipmentResult>> ShipOrder(Guid orderId, [FromBody] ShipOrderRequest request)
    {
        try
        {
            // Get the order
            var order = await _orderService.GetOrderByIdAsync(orderId);
            if (order == null)
            {
                return NotFound(new { Error = "Order not found" });
            }

            // Calculate total weight from order items
            var totalWeight = order.Items.Sum(item => 
            {
                // Estimate weight if not available (you might want to add weight to ProductDto)
                return item.Quantity * 200; // Default 200g per item
            });

            // Create shipment request
            var shipmentRequest = new CreateShipmentRequest
            {
                RecipientName = order.ShippingName,
                AddressLine1 = order.ShippingAddress,
                City = order.ShippingCity,
                PostCode = order.ShippingPostCode,
                Country = order.ShippingCountry,
                WeightInGrams = totalWeight,
                Value = order.TotalAmount,
                ServiceCode = request.ServiceCode ?? "1st Class",
                Reference = $"Order-{order.Id}"
            };

            var result = await _royalMailService.CreateShipmentAsync(shipmentRequest);
            
            if (result.Success && !string.IsNullOrEmpty(result.TrackingNumber))
            {
                // Update order with tracking information
                var updateRequest = new UpdateOrderStatusDto
                {
                    Status = Enums.OrderStatus.Shipped,
                    TrackingNumber = result.TrackingNumber
                };

                await _orderService.UpdateOrderStatusAsync(orderId, updateRequest);
                
                _logger.LogInformation("Order {OrderId} shipped with tracking {TrackingNumber}", 
                    orderId, result.TrackingNumber);
            }

            return Ok(result);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error shipping order {OrderId}", orderId);
            return StatusCode(500, new { Error = "Error creating shipment for order" });
        }
    }

    [HttpGet("track/{trackingNumber}")]
    [AllowAnonymous]
    public async Task<ActionResult<TrackingResult>> GetTrackingInfo(string trackingNumber)
    {
        try
        {
            var result = await _royalMailService.GetTrackingInfoAsync(trackingNumber);
            return Ok(result);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error getting tracking info for {TrackingNumber}", trackingNumber);
            return StatusCode(500, new { Error = "Error retrieving tracking information" });
        }
    }

    [HttpGet("services")]
    [AllowAnonymous]
    public async Task<ActionResult<List<RoyalMailServiceOption>>> GetAvailableServices(
        [FromQuery] decimal weight = 500, 
        [FromQuery] string country = "United Kingdom")
    {
        try
        {
            var services = await _royalMailService.GetAvailableServicesAsync(weight, country);
            return Ok(services);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error getting Royal Mail services");
            return StatusCode(500, new { Error = "Error retrieving shipping services" });
        }
    }

    [HttpGet("labels/{shipmentId}")]
    [Authorize(Roles = "Admin")]
    public async Task<IActionResult> GetShippingLabel(string shipmentId)
    {
        try
        {
            var labelData = await _royalMailService.GenerateShippingLabelAsync(shipmentId);
            
            if (labelData != null)
            {
                return File(labelData, "application/pdf", $"shipping-label-{shipmentId}.pdf");
            }
            
            return NotFound(new { Error = "Shipping label not found" });
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error generating shipping label for {ShipmentId}", shipmentId);
            return StatusCode(500, new { Error = "Error generating shipping label" });
        }
    }

    [HttpDelete("{shipmentId}")]
    [Authorize(Roles = "Admin")]
    public async Task<IActionResult> CancelShipment(string shipmentId)
    {
        try
        {
            var result = await _royalMailService.CancelShipmentAsync(shipmentId);
            
            if (result)
            {
                return Ok(new { Message = "Shipment cancelled successfully" });
            }
            
            return BadRequest(new { Error = "Failed to cancel shipment" });
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error cancelling shipment {ShipmentId}", shipmentId);
            return StatusCode(500, new { Error = "Error cancelling shipment" });
        }
    }
}

public class CalculateShippingRequest
{
    public decimal WeightInGrams { get; set; }
    public string Country { get; set; } = "United Kingdom";
}

public class ShipOrderRequest
{
    public string? ServiceCode { get; set; }
}

public class ShippingCalculationResult
{
    public bool Success { get; set; }
    public List<ShippingOption> Services { get; set; } = new();
    public string? ErrorMessage { get; set; }
}

public class ShippingOption
{
    public string ServiceCode { get; set; } = string.Empty;
    public string ServiceName { get; set; } = string.Empty;
    public string Description { get; set; } = string.Empty;
    public decimal Cost { get; set; }
    public int EstimatedDeliveryDays { get; set; }
    public bool SupportsTracking { get; set; }
}