package entities

import (
	"database/sql/driver"
	"encoding/json"
	"errors"
	"time"

	"github.com/google/uuid"
	"gorm.io/gorm"
)

type Modifiers []map[string]interface{}

func (m Modifiers) Value() (driver.Value, error) {
	return json.Marshal(m)
}

func (m *Modifiers) Scan(value interface{}) error {
	if value == nil {
		*m = make(Modifiers, 0)
		return nil
	}

	bytes, ok := value.([]byte)
	if !ok {
		return errors.New("type assertion to []byte failed")
	}

	return json.Unmarshal(bytes, m)
}

type OrderItemStatus string

const (
	OrderItemStatusPending   OrderItemStatus = "pending"
	OrderItemStatusPreparing OrderItemStatus = "preparing"
	OrderItemStatusReady     OrderItemStatus = "ready"
	OrderItemStatusServed    OrderItemStatus = "served"
	OrderItemStatusCancelled OrderItemStatus = "cancelled"
	OrderItemStatusPaid      OrderItemStatus = "paid"
)

type OrderItem struct {
	ID                  uuid.UUID       `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"`
	OrderID             uuid.UUID       `gorm:"type:uuid;not null;index" json:"order_id" validate:"required"`
	ProductID           uuid.UUID       `gorm:"type:uuid;not null;index" json:"product_id" validate:"required"`
	ProductVariantID    *uuid.UUID      `gorm:"type:uuid;index" json:"product_variant_id"`
	Quantity            int             `gorm:"not null" json:"quantity" validate:"required,min=1"`
	UnitPrice           float64         `gorm:"type:decimal(10,2);not null" json:"unit_price" validate:"required,min=0"`
	TotalPrice          float64         `gorm:"type:decimal(10,2);not null" json:"total_price" validate:"required,min=0"`
	UnitCost            float64         `gorm:"type:decimal(10,2);default:0.00" json:"unit_cost"`
	TotalCost           float64         `gorm:"type:decimal(10,2);default:0.00" json:"total_cost"`
	RefundAmount        float64         `gorm:"type:decimal(10,2);default:0.00" json:"refund_amount"`
	RefundQuantity      int             `gorm:"default:0" json:"refund_quantity"`
	IsPartiallyRefunded bool            `gorm:"default:false" json:"is_partially_refunded"`
	IsFullyRefunded     bool            `gorm:"default:false" json:"is_fully_refunded"`
	RefundReason        *string         `gorm:"size:255" json:"refund_reason,omitempty"`
	RefundedAt          *time.Time      `gorm:"" json:"refunded_at,omitempty"`
	RefundedBy          *uuid.UUID      `gorm:"type:uuid" json:"refunded_by,omitempty"`
	Modifiers           Modifiers       `gorm:"type:jsonb;default:'[]'" json:"modifiers"`
	Notes               *string         `gorm:"size:500" json:"notes,omitempty"`
	Metadata            Metadata        `gorm:"type:jsonb;default:'{}'" json:"metadata"`
	Status              OrderItemStatus `gorm:"default:'pending';size:50" json:"status"`
	CreatedAt           time.Time       `gorm:"autoCreateTime" json:"created_at"`
	UpdatedAt           time.Time       `gorm:"autoUpdateTime" json:"updated_at"`

	Order          Order           `gorm:"foreignKey:OrderID" json:"order,omitempty"`
	Product        Product         `gorm:"foreignKey:ProductID" json:"product,omitempty"`
	ProductVariant *ProductVariant `gorm:"foreignKey:ProductVariantID" json:"product_variant,omitempty"`
}

func (oi *OrderItem) BeforeCreate(tx *gorm.DB) error {
	if oi.ID == uuid.Nil {
		oi.ID = uuid.New()
	}
	return nil
}

func (OrderItem) TableName() string {
	return "order_items"
}

func (oi *OrderItem) CalculateTotalPrice() {
	oi.TotalPrice = float64(oi.Quantity) * oi.UnitPrice
}

func (oi *OrderItem) CanBeModified() bool {
	return oi.Status == OrderItemStatusPending
}
