using Microsoft.EntityFrameworkCore;
using LittleShop.Data;
using LittleShop.Models;
using LittleShop.DTOs;

namespace LittleShop.Services;

public interface IShippingRateService
{
    Task<IEnumerable<ShippingRateDto>> GetAllShippingRatesAsync();
    Task<ShippingRateDto?> GetShippingRateByIdAsync(Guid id);
    Task<ShippingRateDto> CreateShippingRateAsync(CreateShippingRateDto dto);
    Task<bool> UpdateShippingRateAsync(Guid id, UpdateShippingRateDto dto);
    Task<bool> DeleteShippingRateAsync(Guid id);
    Task<ShippingRateDto?> CalculateShippingAsync(decimal weight, string country);
}

public class ShippingRateService : IShippingRateService
{
    private readonly LittleShopContext _context;
    private readonly ILogger<ShippingRateService> _logger;

    public ShippingRateService(LittleShopContext context, ILogger<ShippingRateService> logger)
    {
        _context = context;
        _logger = logger;
    }

    public async Task<IEnumerable<ShippingRateDto>> GetAllShippingRatesAsync()
    {
        var rates = await _context.ShippingRates
            .OrderBy(sr => sr.Country)
            .ToListAsync();

        // Sort by MinWeight in memory to avoid SQLite decimal ordering issue
        return rates.OrderBy(sr => sr.MinWeight).Select(MapToDto);
    }

    public async Task<ShippingRateDto?> GetShippingRateByIdAsync(Guid id)
    {
        var rate = await _context.ShippingRates.FindAsync(id);
        return rate == null ? null : MapToDto(rate);
    }

    public async Task<ShippingRateDto> CreateShippingRateAsync(CreateShippingRateDto dto)
    {
        var rate = new ShippingRate
        {
            Id = Guid.NewGuid(),
            Name = dto.Name,
            Description = dto.Description,
            Country = dto.Country,
            MinWeight = dto.MinWeight,
            MaxWeight = dto.MaxWeight,
            Price = dto.Price,
            MinDeliveryDays = dto.MinDeliveryDays,
            MaxDeliveryDays = dto.MaxDeliveryDays,
            IsActive = dto.IsActive,
            CreatedAt = DateTime.UtcNow,
            UpdatedAt = DateTime.UtcNow
        };

        _context.ShippingRates.Add(rate);
        await _context.SaveChangesAsync();

        _logger.LogInformation("Created shipping rate {RateId} for {Country}: {Name}", 
            rate.Id, rate.Country, rate.Name);

        return MapToDto(rate);
    }

    public async Task<bool> UpdateShippingRateAsync(Guid id, UpdateShippingRateDto dto)
    {
        var rate = await _context.ShippingRates.FindAsync(id);
        if (rate == null)
            return false;

        rate.Name = dto.Name;
        rate.Description = dto.Description;
        rate.Country = dto.Country;
        rate.MinWeight = dto.MinWeight;
        rate.MaxWeight = dto.MaxWeight;
        rate.Price = dto.Price;
        rate.MinDeliveryDays = dto.MinDeliveryDays;
        rate.MaxDeliveryDays = dto.MaxDeliveryDays;
        rate.IsActive = dto.IsActive;
        rate.UpdatedAt = DateTime.UtcNow;

        await _context.SaveChangesAsync();

        _logger.LogInformation("Updated shipping rate {RateId}", id);
        return true;
    }

    public async Task<bool> DeleteShippingRateAsync(Guid id)
    {
        var rate = await _context.ShippingRates.FindAsync(id);
        if (rate == null)
            return false;

        _context.ShippingRates.Remove(rate);
        await _context.SaveChangesAsync();

        _logger.LogInformation("Deleted shipping rate {RateId}", id);
        return true;
    }

    public async Task<ShippingRateDto?> CalculateShippingAsync(decimal weight, string country)
    {
        // Convert weight to grams for comparison
        var weightInGrams = weight * 1000; // Assuming weight is in kg

        var rate = await _context.ShippingRates
            .Where(sr => sr.IsActive 
                && sr.Country.ToLower() == country.ToLower()
                && sr.MinWeight <= weightInGrams 
                && sr.MaxWeight >= weightInGrams)
            .OrderBy(sr => sr.Price)
            .FirstOrDefaultAsync();

        return rate == null ? null : MapToDto(rate);
    }

    private static ShippingRateDto MapToDto(ShippingRate rate)
    {
        return new ShippingRateDto
        {
            Id = rate.Id,
            Name = rate.Name,
            Description = rate.Description,
            Country = rate.Country,
            MinWeight = rate.MinWeight,
            MaxWeight = rate.MaxWeight,
            Price = rate.Price,
            MinDeliveryDays = rate.MinDeliveryDays,
            MaxDeliveryDays = rate.MaxDeliveryDays,
            IsActive = rate.IsActive,
            CreatedAt = rate.CreatedAt,
            UpdatedAt = rate.UpdatedAt
        };
    }
}