using CMSMicroservice.Protobuf.Protos.DiscountOrder;
using Google.Protobuf.WellKnownTypes;
using ProtoDeliveryStatus = CMSMicroservice.Protobuf.Protos.DiscountOrder.DeliveryStatus;
using ProtoPaymentStatus = CMSMicroservice.Protobuf.Protos.DiscountOrder.PaymentStatus;

namespace BackOffice.Services.DiscountOrder;

public class DiscountOrderService : IDiscountOrderService
{
    private readonly DiscountOrderContract.DiscountOrderContractClient _client;

    public DiscountOrderService(DiscountOrderContract.DiscountOrderContractClient client)
    {
        _client = client;
    }

    public async Task<(List<DiscountOrderDto> Orders, int TotalCount, int TotalPages)> GetOrdersAsync(OrderFilterDto? filter = null)
    {
        filter ??= new OrderFilterDto();

        // استفاده از Admin RPC برای دسترسی به فیلدهای کامل
        var request = new GetAllDiscountOrdersRequest
        {
            PageNumber = filter.PageNumber,
            PageSize = filter.PageSize
        };

        if (filter.UserId.HasValue)
            request.UserId = filter.UserId.Value;
        if (filter.PaymentStatus.HasValue)
            request.PaymentStatus = filter.PaymentStatus.Value;
        if (filter.Status.HasValue)
            request.DeliveryStatus = (int)MapToProtoStatus(filter.Status.Value);
        if (!string.IsNullOrEmpty(filter.UserMobile))
            request.UserMobile = filter.UserMobile;
        if (!string.IsNullOrEmpty(filter.TrackingCode))
            request.TrackingCode = filter.TrackingCode;
        if (filter.FromDate.HasValue)
            request.FromDate = Timestamp.FromDateTime(filter.FromDate.Value.ToUniversalTime());
        if (filter.ToDate.HasValue)
            request.ToDate = Timestamp.FromDateTime(filter.ToDate.Value.ToUniversalTime());
        if (filter.MinAmount.HasValue)
            request.MinAmount = filter.MinAmount.Value;
        if (filter.MaxAmount.HasValue)
            request.MaxAmount = filter.MaxAmount.Value;

        var response = await _client.GetAllDiscountOrdersAsync(request);

        var orders = response.Models.Select(o => new DiscountOrderDto
        {
            Id = o.Id,
            OrderNumber = o.Id.ToString(),
            UserId = o.UserId,
            UserFullName = o.UserFullName,
            UserMobile = o.UserMobile,
            TotalPrice = o.TotalAmount,
            DiscountBalanceUsed = o.DiscountBalanceUsed,
            GatewayAmount = o.GatewayAmountPaid,
            VatAmount = o.VatAmount,
            PaymentCompleted = o.PaymentStatus == ProtoPaymentStatus.PaymentCompleted,
            PaymentStatusValue = (int)o.PaymentStatus,
            Status = MapFromProtoDeliveryStatus(o.DeliveryStatus),
            TrackingCode = o.TrackingCode,
            ShippingAddress = o.ShippingAddress,
            ItemsCount = o.ItemsCount,
            PaymentDate = o.PaymentDate?.ToDateTime(),
            Created = o.Created?.ToDateTime()
        }).ToList();

        var totalCount = (int)(response.MetaData?.TotalCount ?? 0);
        var totalPages = (int)(response.MetaData?.TotalPage ?? 0);

        return (orders, totalCount, totalPages);
    }

    public async Task<DiscountOrderDetailsDto?> GetByIdAsync(long orderId, long? userId = null)
    {
        var request = new GetOrderByIdRequest 
        { 
            OrderId = orderId,
            UserId = userId ?? 0
        };
        var response = await _client.GetOrderByIdAsync(request);

        if (response == null || response.Id == 0)
            return null;

        return new DiscountOrderDetailsDto
        {
            Id = response.Id,
            UserId = response.UserId,
            OrderNumber = response.OrderNumber,
            Address = response.Address != null ? new AddressInfoDto
            {
                Id = response.Address.Id,
                Title = response.Address.Title,
                Address = response.Address.Address,
                PostalCode = response.Address.PostalCode,
                Phone = response.Address.Phone
            } : null,
            TotalPrice = response.TotalPrice,
            DiscountBalanceUsed = response.DiscountBalanceUsed,
            GatewayAmount = response.GatewayAmount,
            PaymentCompleted = response.PaymentCompleted,
            PaymentStatusValue = (int)response.PaymentStatus,
            TransactionId = response.TransactionId,
            Status = MapFromProtoStatus(response.DeliveryStatus, response.PaymentCompleted),
            TrackingCode = response.TrackingCode,
            Notes = response.Notes,
            AdminNotes = response.AdminNotes,
            Items = response.Items.Select(item => new OrderItemDto
            {
                ProductId = item.ProductId,
                ProductTitle = item.ProductTitle,
                UnitPrice = item.UnitPrice,
                MaxDiscountPercent = item.MaxDiscountPercent,
                Count = item.Count,
                TotalPrice = item.TotalPrice,
                DiscountAmount = item.DiscountAmount,
                FinalPrice = item.FinalPrice,
                ImagePath = item.ImagePath,
                ThumbnailPath = item.ThumbnailPath
            }).ToList(),
            Created = response.Created?.ToDateTime(),
            LastModified = response.LastModified?.ToDateTime()
        };
    }

    public async Task UpdateStatusAsync(long orderId, UpdateOrderStatusDto dto)
    {
        var request = new UpdateOrderStatusRequest
        {
            OrderId = orderId,
            DeliveryStatus = MapToProtoStatus(dto.Status)
        };

        if (!string.IsNullOrEmpty(dto.TrackingCode))
            request.TrackingCode = dto.TrackingCode;
        if (!string.IsNullOrEmpty(dto.AdminNotes))
            request.AdminNotes = dto.AdminNotes;

        await _client.UpdateOrderStatusAsync(request);
    }

    public async Task<DiscountSalesReportDto> GetSalesReportAsync(DateTime fromDate, DateTime toDate)
    {
        var request = new GetDiscountSalesReportRequest
        {
            FromDate = Timestamp.FromDateTime(fromDate.ToUniversalTime()),
            ToDate = Timestamp.FromDateTime(toDate.ToUniversalTime()),
            ReportType = SalesReportType.ReportDaily
        };

        var response = await _client.GetDiscountSalesReportAsync(request);

        var result = new DiscountSalesReportDto();

        if (response.Summary != null)
        {
            result.Summary = new SalesSummaryDto
            {
                TotalOrders = response.Summary.TotalOrders,
                CompletedOrders = response.Summary.CompletedOrders,
                PendingOrders = response.Summary.PendingOrders,
                CancelledOrders = response.Summary.CancelledOrders,
                TotalSalesAmount = response.Summary.TotalSalesAmount,
                TotalDiscountUsed = response.Summary.TotalDiscountUsed,
                TotalGatewayPaid = response.Summary.TotalGatewayPaid,
                TotalVatAmount = response.Summary.TotalVatAmount,
                AverageOrderValue = response.Summary.AverageOrderValue,
                UniqueCustomers = response.Summary.UniqueCustomers,
                TotalProductsSold = response.Summary.TotalProductsSold
            };
        }

        result.Periods = response.Periods.Select(p => new SalesPeriodItemDto
        {
            PeriodLabel = p.PeriodLabel,
            OrdersCount = p.OrdersCount,
            TotalAmount = p.TotalAmount,
            DiscountUsed = p.DiscountUsed,
            GatewayPaid = p.GatewayPaid
        }).ToList();

        result.TopProducts = response.TopProducts.Select(tp => new TopSellingProductItemDto
        {
            ProductId = tp.ProductId,
            ProductTitle = tp.ProductTitle,
            ImagePath = tp.ImagePath,
            QuantitySold = tp.QuantitySold,
            TotalRevenue = tp.TotalRevenue,
            OrdersCount = tp.OrdersCount
        }).ToList();

        return result;
    }

    // Map from UI OrderStatus to Proto DeliveryStatus
    private static ProtoDeliveryStatus MapToProtoStatus(OrderStatus status)
    {
        return status switch
        {
            OrderStatus.Pending => ProtoDeliveryStatus.DeliveryPending,
            OrderStatus.Paid => ProtoDeliveryStatus.DeliveryPending,
            OrderStatus.Processing => ProtoDeliveryStatus.DeliveryProcessing,
            OrderStatus.Shipped => ProtoDeliveryStatus.DeliveryShipped,
            OrderStatus.Delivered => ProtoDeliveryStatus.DeliveryDelivered,
            OrderStatus.Cancelled => ProtoDeliveryStatus.DeliveryCancelled,
            OrderStatus.ReadyForOfficePickup => ProtoDeliveryStatus.DeliveryReadyForOffice,
            OrderStatus.Returned => ProtoDeliveryStatus.DeliveryReturned,
            _ => ProtoDeliveryStatus.DeliveryPending
        };
    }

    // Map from Proto DeliveryStatus to UI OrderStatus (for GetOrderById which uses bool paymentCompleted)
    private static OrderStatus MapFromProtoStatus(ProtoDeliveryStatus status, bool paymentCompleted)
    {
        return status switch
        {
            ProtoDeliveryStatus.DeliveryPending when paymentCompleted => OrderStatus.Paid,
            ProtoDeliveryStatus.DeliveryPending => OrderStatus.Pending,
            ProtoDeliveryStatus.DeliveryProcessing => OrderStatus.Processing,
            ProtoDeliveryStatus.DeliveryShipped => OrderStatus.Shipped,
            ProtoDeliveryStatus.DeliveryDelivered => OrderStatus.Delivered,
            ProtoDeliveryStatus.DeliveryCancelled => OrderStatus.Cancelled,
            ProtoDeliveryStatus.DeliveryReadyForOffice => OrderStatus.ReadyForOfficePickup,
            ProtoDeliveryStatus.DeliveryReturned => OrderStatus.Returned,
            _ => OrderStatus.Pending
        };
    }

    // Map from Proto DeliveryStatus to UI OrderStatus (for GetAllDiscountOrders / AdminOrderDto)
    private static OrderStatus MapFromProtoDeliveryStatus(ProtoDeliveryStatus status)
    {
        return status switch
        {
            ProtoDeliveryStatus.DeliveryPending => OrderStatus.Pending,
            ProtoDeliveryStatus.DeliveryProcessing => OrderStatus.Processing,
            ProtoDeliveryStatus.DeliveryShipped => OrderStatus.Shipped,
            ProtoDeliveryStatus.DeliveryDelivered => OrderStatus.Delivered,
            ProtoDeliveryStatus.DeliveryCancelled => OrderStatus.Cancelled,
            ProtoDeliveryStatus.DeliveryReadyForOffice => OrderStatus.ReadyForOfficePickup,
            ProtoDeliveryStatus.DeliveryReturned => OrderStatus.Returned,
            _ => OrderStatus.Pending
        };
    }
}
