package models

import (
	"apskel-pos-be/internal/constants"
	"time"

	"github.com/google/uuid"
)

type Order struct {
	ID              uuid.UUID
	OrganizationID  uuid.UUID
	OutletID        uuid.UUID
	UserID          uuid.UUID
	CustomerID      *uuid.UUID
	OrderNumber     string
	TableNumber     *string
	OrderType       constants.OrderType
	Status          constants.OrderStatus
	Subtotal        float64
	TaxAmount       float64
	DiscountAmount  float64
	TotalAmount     float64
	TotalCost       float64
	RemainingAmount float64
	PaymentStatus   constants.PaymentStatus
	RefundAmount    float64
	IsVoid          bool
	IsRefund        bool
	VoidReason      *string
	VoidedAt        *time.Time
	VoidedBy        *uuid.UUID
	RefundReason    *string
	RefundedAt      *time.Time
	RefundedBy      *uuid.UUID
	Metadata        map[string]interface{}
	CreatedAt       time.Time
	UpdatedAt       time.Time
}

type OrderItem struct {
	ID                  uuid.UUID
	OrderID             uuid.UUID
	ProductID           uuid.UUID
	ProductVariantID    *uuid.UUID
	Quantity            int
	UnitPrice           float64
	TotalPrice          float64
	UnitCost            float64
	TotalCost           float64
	RefundAmount        float64
	RefundQuantity      int
	IsPartiallyRefunded bool
	IsFullyRefunded     bool
	RefundReason        *string
	RefundedAt          *time.Time
	RefundedBy          *uuid.UUID
	Modifiers           []map[string]interface{}
	Status              constants.OrderItemStatus
	CreatedAt           time.Time
	UpdatedAt           time.Time
}

type PaymentOrderItem struct {
	ID          uuid.UUID
	PaymentID   uuid.UUID
	OrderItemID uuid.UUID
	Quantity    int // Quantity paid for this specific payment
	Amount      float64
	CreatedAt   time.Time
	UpdatedAt   time.Time
}

type OrderSequence struct {
	ID             uuid.UUID
	OrganizationID uuid.UUID
	OutletID       uuid.UUID
	Year           int
	Month          int
	SequenceNumber int
	CreatedAt      time.Time
	UpdatedAt      time.Time
}

type CreateOrderRequest struct {
	OutletID     uuid.UUID                `validate:"required"`
	UserID       uuid.UUID                `validate:"required"`
	CustomerID   *uuid.UUID               `validate:"omitempty"`
	TableID      *uuid.UUID               `validate:"omitempty"`
	TableNumber  *string                  `validate:"omitempty,max=50"`
	OrderType    constants.OrderType      `validate:"required"`
	OrderItems   []CreateOrderItemRequest `validate:"required,min=1,dive"`
	Notes        *string                  `validate:"omitempty,max=1000"`
	Metadata     map[string]interface{}
	CustomerName *string `validate:"omitempty,max=255"`
}

type CreateOrderItemRequest struct {
	ProductID        uuid.UUID                `validate:"required"`
	ProductVariantID *uuid.UUID               `validate:"omitempty"`
	Quantity         int                      `validate:"required,min=1"`
	UnitPrice        *float64                 `validate:"omitempty,min=0"` // Optional, will use database price if not provided
	Modifiers        []map[string]interface{} `validate:"omitempty"`
	Notes            *string                  `validate:"omitempty,max=500"`
	Metadata         map[string]interface{}   `validate:"omitempty"`
}

type UpdateOrderRequest struct {
	TableNumber    *string                `validate:"omitempty,max=50"`
	Status         *constants.OrderStatus `validate:"omitempty"`
	DiscountAmount *float64               `validate:"omitempty,min=0"`
	Notes          *string                `validate:"omitempty,max=1000"`
	Metadata       map[string]interface{}
}

type CreatePaymentOrderItemRequest struct {
	OrderItemID uuid.UUID `validate:"required"`
	Quantity    int       `validate:"required,min=1"` // Quantity being paid for
	Amount      float64   `validate:"required,min=0"`
}

type VoidOrderRequest struct {
	OrderID uuid.UUID         `validate:"required"`
	Reason  string            `validate:"required"`
	Type    string            `validate:"required,oneof=ALL ITEM"`
	Items   []VoidItemRequest `validate:"required_if=Type ITEM,dive"`
}

type VoidItemRequest struct {
	OrderItemID uuid.UUID `validate:"required"`
	Quantity    int       `validate:"required,min=1"`
}

type RefundOrderRequest struct {
	Reason       *string                  `validate:"omitempty,max=255"`
	RefundAmount *float64                 `validate:"omitempty,min=0"`
	OrderItems   []RefundOrderItemRequest `validate:"omitempty,dive"`
}

type RefundOrderItemRequest struct {
	OrderItemID    uuid.UUID `validate:"required"`
	RefundQuantity int       `validate:"omitempty,min=1"`
	RefundAmount   *float64  `validate:"omitempty,min=0"`
	Reason         *string   `validate:"omitempty,max=255"`
}

type OrderResponse struct {
	ID              uuid.UUID
	OrganizationID  uuid.UUID
	OutletID        uuid.UUID
	UserID          uuid.UUID
	CustomerID      *uuid.UUID
	OrderNumber     string
	TableNumber     *string
	OrderType       constants.OrderType
	Status          constants.OrderStatus
	Subtotal        float64
	TaxAmount       float64
	DiscountAmount  float64
	TotalAmount     float64
	TotalCost       float64
	RemainingAmount float64
	PaymentStatus   constants.PaymentStatus
	RefundAmount    float64
	IsVoid          bool
	IsRefund        bool
	VoidReason      *string
	VoidedAt        *time.Time
	VoidedBy        *uuid.UUID
	RefundReason    *string
	RefundedAt      *time.Time
	RefundedBy      *uuid.UUID
	Notes           *string
	Metadata        map[string]interface{}
	CreatedAt       time.Time
	UpdatedAt       time.Time
	OrderItems      []OrderItemResponse
	Payments        []PaymentResponse
	TotalPaid       float64
	PaymentCount    int
	SplitType       *string
}

type OrderItemResponse struct {
	ID                  uuid.UUID
	OrderID             uuid.UUID
	ProductID           uuid.UUID
	ProductName         string
	ProductVariantID    *uuid.UUID
	ProductVariantName  *string
	Quantity            int
	UnitPrice           float64
	TotalPrice          float64
	UnitCost            float64
	TotalCost           float64
	RefundAmount        float64
	RefundQuantity      int
	IsPartiallyRefunded bool
	IsFullyRefunded     bool
	RefundReason        *string
	RefundedAt          *time.Time
	RefundedBy          *uuid.UUID
	Modifiers           []map[string]interface{}
	Notes               *string
	Metadata            map[string]interface{}
	Status              constants.OrderItemStatus
	CreatedAt           time.Time
	UpdatedAt           time.Time
	PrinterType         string
	PaidQuantity        int
}

type PaymentOrderItemResponse struct {
	ID          uuid.UUID
	PaymentID   uuid.UUID
	OrderItemID uuid.UUID
	Quantity    int // Quantity paid for this specific payment
	Amount      float64
	CreatedAt   time.Time
	UpdatedAt   time.Time
}

type ListOrdersRequest struct {
	OrganizationID *uuid.UUID
	OutletID       *uuid.UUID
	UserID         *uuid.UUID
	CustomerID     *uuid.UUID
	OrderType      *constants.OrderType
	Status         *constants.OrderStatus
	PaymentStatus  *constants.PaymentStatus
	IsVoid         *bool
	IsRefund       *bool
	DateFrom       *time.Time
	DateTo         *time.Time
	Search         string
	Page           int `validate:"required,min=1"`
	Limit          int `validate:"required,min=1,max=100"`
}

type ListOrdersResponse struct {
	Orders     []OrderResponse
	Payments   []PaymentResponse
	TotalCount int
	Page       int
	Limit      int
	TotalPages int
}

func (o *Order) CanBeModified() bool {
	return o.Status == constants.OrderStatusPending || o.Status == constants.OrderStatusPreparing
}

func (o *Order) CanBeCancelled() bool {
	return o.Status == constants.OrderStatusPending || o.Status == constants.OrderStatusPreparing
}

func (o *Order) CalculateTotalAmount(taxRate float64) float64 {
	taxAmount := o.Subtotal * taxRate
	return o.Subtotal + taxAmount - o.DiscountAmount
}

func (o *Order) IsComplete() bool {
	return o.Status == constants.OrderStatusCompleted
}

func (o *Order) IsPaid() bool {
	return o.Status == constants.OrderStatusPaid
}

func (r *CreateOrderRequest) Validate() bool {
	return r.OrderType.IsValidOrderType()
}

// AddToOrderRequest represents the request to add items to an existing order
type AddToOrderRequest struct {
	OrderItems []CreateOrderItemRequest `validate:"required,min=1,dive"`
	Notes      *string                  `validate:"omitempty,max=1000"`
	Metadata   map[string]interface{}   `validate:"omitempty"`
}

// AddToOrderResponse represents the response when adding items to an existing order
type AddToOrderResponse struct {
	OrderID      uuid.UUID
	OrderNumber  string
	AddedItems   []OrderItemResponse
	UpdatedOrder OrderResponse
}

// SetOrderCustomerRequest represents the request to set customer for an order
type SetOrderCustomerRequest struct {
	CustomerID uuid.UUID `validate:"required"`
}

// SetOrderCustomerResponse represents the response when setting customer for an order
type SetOrderCustomerResponse struct {
	OrderID    uuid.UUID
	CustomerID uuid.UUID
	Message    string
}
