package transformer

import (
	"apskel-pos-be/internal/constants"
	"apskel-pos-be/internal/contract"
	"apskel-pos-be/internal/models"
	"apskel-pos-be/internal/util"
	"strconv"

	"github.com/google/uuid"
)

func CreateOrderContractToModel(req *contract.CreateOrderRequest) *models.CreateOrderRequest {
	items := make([]models.CreateOrderItemRequest, len(req.OrderItems))
	for i, item := range req.OrderItems {
		items[i] = models.CreateOrderItemRequest{
			ProductID:        item.ProductID,
			ProductVariantID: item.ProductVariantID,
			Quantity:         item.Quantity,
			UnitPrice:        item.UnitPrice, // Now optional
			Modifiers:        item.Modifiers,
			Notes:            item.Notes,
			Metadata:         item.Metadata,
		}
	}
	return &models.CreateOrderRequest{
		OutletID:     req.OutletID,
		UserID:       req.UserID,
		TableID:      req.TableID,
		TableNumber:  req.TableNumber,
		OrderType:    constants.OrderType(req.OrderType),
		OrderItems:   items,
		Notes:        req.Notes,
		CustomerName: req.CustomerName,
	}
}

func UpdateOrderContractToModel(req *contract.UpdateOrderRequest) *models.UpdateOrderRequest {
	var status *constants.OrderStatus

	if req.Status != nil {
		stats := constants.OrderStatus(*req.Status)
		status = &stats
	}
	return &models.UpdateOrderRequest{
		TableNumber:    req.TableNumber,
		Status:         status,
		DiscountAmount: req.DiscountAmount,
		Notes:          req.Notes,
		Metadata:       req.Metadata,
	}
}

func AddToOrderContractToModel(req *contract.AddToOrderRequest) *models.AddToOrderRequest {
	items := make([]models.CreateOrderItemRequest, len(req.OrderItems))
	for i, item := range req.OrderItems {
		items[i] = models.CreateOrderItemRequest{
			ProductID:        item.ProductID,
			ProductVariantID: item.ProductVariantID,
			Quantity:         item.Quantity,
			UnitPrice:        item.UnitPrice, // Now optional
			Modifiers:        item.Modifiers,
			Notes:            item.Notes,
			Metadata:         item.Metadata,
		}
	}
	return &models.AddToOrderRequest{
		OrderItems: items,
		Notes:      req.Notes,
		Metadata:   req.Metadata,
	}
}

func VoidOrderContractToModel(req *contract.VoidOrderRequest) *models.VoidOrderRequest {
	items := make([]models.VoidItemRequest, len(req.Items))
	for i, item := range req.Items {
		items[i] = models.VoidItemRequest{
			OrderItemID: item.OrderItemID,
			Quantity:    item.Quantity,
		}
	}
	return &models.VoidOrderRequest{
		OrderID: req.OrderID,
		Reason:  req.Reason,
		Type:    req.Type,
		Items:   items,
	}
}

func OrderModelToContract(resp *models.OrderResponse) *contract.OrderResponse {
	if resp == nil {
		return nil
	}
	items := make([]contract.OrderItemResponse, len(resp.OrderItems))
	for i, item := range resp.OrderItems {
		items[i] = contract.OrderItemResponse{
			ID:                 item.ID,
			OrderID:            item.OrderID,
			ProductID:          item.ProductID,
			ProductName:        item.ProductName,
			ProductVariantID:   item.ProductVariantID,
			ProductVariantName: item.ProductVariantName,
			Quantity:           item.Quantity,
			UnitPrice:          item.UnitPrice,
			TotalPrice:         item.TotalPrice,
			Modifiers:          item.Modifiers,
			Notes:              item.Notes,
			Metadata:           item.Metadata,
			Status:             string(item.Status),
			CreatedAt:          item.CreatedAt,
			UpdatedAt:          item.UpdatedAt,
			PrinterType:        item.PrinterType,
			PaidQuantity:       item.PaidQuantity,
		}
	}
	// Map payments
	payments := make([]contract.PaymentResponse, len(resp.Payments))
	for i, payment := range resp.Payments {
		payments[i] = *PaymentModelToContract(&payment)
	}

	return &contract.OrderResponse{
		ID:              resp.ID,
		OrderNumber:     resp.OrderNumber,
		OutletID:        resp.OutletID,
		UserID:          resp.UserID,
		TableNumber:     resp.TableNumber,
		OrderType:       string(resp.OrderType),
		Status:          string(resp.Status),
		Subtotal:        resp.Subtotal,
		TaxAmount:       resp.TaxAmount,
		DiscountAmount:  resp.DiscountAmount,
		TotalAmount:     resp.TotalAmount,
		TotalCost:       resp.TotalCost,
		RemainingAmount: resp.RemainingAmount,
		PaymentStatus:   string(resp.PaymentStatus),
		RefundAmount:    resp.RefundAmount,
		IsVoid:          resp.IsVoid,
		IsRefund:        resp.IsRefund,
		VoidReason:      resp.VoidReason,
		VoidedAt:        resp.VoidedAt,
		VoidedBy:        resp.VoidedBy,
		RefundReason:    resp.RefundReason,
		RefundedAt:      resp.RefundedAt,
		RefundedBy:      resp.RefundedBy,
		Notes:           resp.Notes,
		Metadata:        resp.Metadata,
		CreatedAt:       resp.CreatedAt,
		UpdatedAt:       resp.UpdatedAt,
		OrderItems:      items,
		Payments:        payments,
		TotalPaid:       resp.TotalPaid,
		PaymentCount:    resp.PaymentCount,
		SplitType:       resp.SplitType,
	}
}

func AddToOrderModelToContract(resp *models.AddToOrderResponse) *contract.AddToOrderResponse {
	if resp == nil {
		return nil
	}
	items := make([]contract.OrderItemResponse, len(resp.AddedItems))
	for i, item := range resp.AddedItems {
		items[i] = contract.OrderItemResponse{
			ID:                 item.ID,
			OrderID:            item.OrderID,
			ProductID:          item.ProductID,
			ProductName:        item.ProductName,
			ProductVariantID:   item.ProductVariantID,
			ProductVariantName: item.ProductVariantName,
			Quantity:           item.Quantity,
			UnitPrice:          item.UnitPrice,
			TotalPrice:         item.TotalPrice,
			Modifiers:          item.Modifiers,
			Notes:              item.Notes,
			Metadata:           item.Metadata,
			Status:             string(item.Status),
			CreatedAt:          item.CreatedAt,
			UpdatedAt:          item.UpdatedAt,
		}
	}
	return &contract.AddToOrderResponse{
		OrderID:      resp.OrderID,
		OrderNumber:  resp.OrderNumber,
		AddedItems:   items,
		UpdatedOrder: *OrderModelToContract(&resp.UpdatedOrder),
	}
}

func SetOrderCustomerContractToModel(req *contract.SetOrderCustomerRequest) *models.SetOrderCustomerRequest {
	return &models.SetOrderCustomerRequest{
		CustomerID: req.CustomerID,
	}
}

func SetOrderCustomerModelToContract(resp *models.SetOrderCustomerResponse) *contract.SetOrderCustomerResponse {
	if resp == nil {
		return nil
	}
	return &contract.SetOrderCustomerResponse{
		OrderID:    resp.OrderID,
		CustomerID: resp.CustomerID,
		Message:    resp.Message,
	}
}

func ListOrdersQueryToModel(query *contract.ListOrdersQuery) *models.ListOrdersRequest {
	req := &models.ListOrdersRequest{
		Search: query.Search,
		Page:   query.Page,
		Limit:  query.Limit,
	}

	if query.OrganizationID != "" {
		if organizationID, err := uuid.Parse(query.OrganizationID); err == nil {
			req.OrganizationID = &organizationID
		}
	}

	if query.OutletID != "" {
		if outletID, err := uuid.Parse(query.OutletID); err == nil {
			req.OutletID = &outletID
		}
	}

	if query.UserID != "" {
		if userID, err := uuid.Parse(query.UserID); err == nil {
			req.UserID = &userID
		}
	}

	if query.CustomerID != "" {
		if customerID, err := uuid.Parse(query.CustomerID); err == nil {
			req.CustomerID = &customerID
		}
	}

	if query.OrderType != "" {
		orderType := constants.OrderType(query.OrderType)
		req.OrderType = &orderType
	}

	if query.Status != "" {
		status := constants.OrderStatus(query.Status)
		req.Status = &status
	}

	if query.PaymentStatus != "" {
		paymentStatus := constants.PaymentStatus(query.PaymentStatus)
		req.PaymentStatus = &paymentStatus
	}

	if query.IsVoid != "" {
		if isVoid, err := strconv.ParseBool(query.IsVoid); err == nil {
			req.IsVoid = &isVoid
		}
	}

	if query.IsRefund != "" {
		if isRefund, err := strconv.ParseBool(query.IsRefund); err == nil {
			req.IsRefund = &isRefund
		}
	}

	if dateFrom, dateTo, err := util.ParseDateRangeToJakartaTime(query.DateFrom, query.DateTo); err == nil {
		req.DateFrom = dateFrom
		req.DateTo = dateTo
	}

	return req
}

func ListOrdersModelToContract(resp *models.ListOrdersResponse) *contract.ListOrdersResponse {
	if resp == nil {
		return nil
	}

	orders := make([]contract.OrderResponse, len(resp.Orders))
	for i, order := range resp.Orders {
		orders[i] = *OrderModelToContract(&order)
	}

	payments := make([]contract.PaymentResponse, len(resp.Payments))
	for i, payment := range resp.Payments {
		payments[i] = *PaymentModelToContract(&payment)
	}

	return &contract.ListOrdersResponse{
		Orders:     orders,
		Payments:   payments,
		TotalCount: resp.TotalCount,
		Page:       resp.Page,
		Limit:      resp.Limit,
		TotalPages: resp.TotalPages,
	}
}

func CreatePaymentContractToModel(req *contract.CreatePaymentRequest) *models.CreatePaymentRequest {
	paymentOrderItems := make([]models.CreatePaymentOrderItemRequest, len(req.PaymentOrderItems))
	for i, item := range req.PaymentOrderItems {
		paymentOrderItems[i] = models.CreatePaymentOrderItemRequest{
			OrderItemID: item.OrderItemID,
			Amount:      item.Amount,
		}
	}
	return &models.CreatePaymentRequest{
		OrderID:           req.OrderID,
		PaymentMethodID:   req.PaymentMethodID,
		Amount:            req.Amount,
		TransactionID:     req.TransactionID,
		SplitNumber:       req.SplitNumber,
		SplitTotal:        req.SplitTotal,
		SplitDescription:  req.SplitDescription,
		PaymentOrderItems: paymentOrderItems,
		Metadata:          req.Metadata,
	}
}

func PaymentModelToContract(resp *models.PaymentResponse) *contract.PaymentResponse {
	if resp == nil {
		return nil
	}

	paymentOrderItems := make([]contract.PaymentOrderItemResponse, len(resp.PaymentOrderItems))
	for i, item := range resp.PaymentOrderItems {
		paymentOrderItems[i] = contract.PaymentOrderItemResponse{
			ID:          item.ID,
			PaymentID:   item.PaymentID,
			OrderItemID: item.OrderItemID,
			Amount:      item.Amount,
			CreatedAt:   item.CreatedAt,
			UpdatedAt:   item.UpdatedAt,
		}
	}

	return &contract.PaymentResponse{
		ID:                resp.ID,
		OrderID:           resp.OrderID,
		PaymentMethodID:   resp.PaymentMethodID,
		PaymentMethodName: resp.PaymentMethodName,
		PaymentMethodType: string(resp.PaymentMethodType),
		Amount:            resp.Amount,
		Status:            string(resp.Status),
		TransactionID:     resp.TransactionID,
		SplitNumber:       resp.SplitNumber,
		SplitTotal:        resp.SplitTotal,
		SplitType:         resp.SplitType,
		SplitDescription:  resp.SplitDescription,
		RefundAmount:      resp.RefundAmount,
		RefundReason:      resp.RefundReason,
		RefundedAt:        resp.RefundedAt,
		RefundedBy:        resp.RefundedBy,
		Metadata:          resp.Metadata,
		CreatedAt:         resp.CreatedAt,
		UpdatedAt:         resp.UpdatedAt,
		PaymentOrderItems: paymentOrderItems,
	}
}

func RefundOrderContractToModel(req *contract.RefundOrderRequest) *models.RefundOrderRequest {
	orderItems := make([]models.RefundOrderItemRequest, len(req.OrderItems))
	for i, item := range req.OrderItems {
		orderItems[i] = models.RefundOrderItemRequest{
			OrderItemID:    item.OrderItemID,
			RefundQuantity: item.RefundQuantity,
			RefundAmount:   item.RefundAmount,
			Reason:         item.Reason,
		}
	}
	return &models.RefundOrderRequest{
		Reason:       req.Reason,
		RefundAmount: req.RefundAmount,
		OrderItems:   orderItems,
	}
}

func SplitBillContractToModel(req *contract.SplitBillRequest) *models.SplitBillRequest {
	items := make([]models.SplitBillItemRequest, len(req.Items))
	for i, item := range req.Items {
		items[i] = models.SplitBillItemRequest{
			OrderItemID: item.OrderItemID,
			Quantity:    item.Quantity,
		}
	}
	return &models.SplitBillRequest{
		OrderID:         req.OrderID,
		PaymentMethodID: req.PaymentMethodID,
		CustomerID:      req.CustomerID,
		Type:            req.Type,
		Items:           items,
		Amount:          req.Amount,
		OrganizationID:  req.OrganizationID,
	}
}

func SplitBillModelToContract(resp *models.SplitBillResponse) *contract.SplitBillResponse {
	if resp == nil {
		return nil
	}

	items := make([]contract.SplitBillItemResponse, len(resp.Items))
	for i, item := range resp.Items {
		items[i] = contract.SplitBillItemResponse{
			OrderItemID: item.OrderItemID,
			Amount:      item.Amount,
		}
	}

	return &contract.SplitBillResponse{
		PaymentID:  resp.PaymentID,
		OrderID:    resp.OrderID,
		CustomerID: resp.CustomerID,
		Type:       resp.Type,
		Amount:     resp.Amount,
		Items:      items,
		Message:    resp.Message,
	}
}
