package entities

import (
	"database/sql/driver"
	"encoding/json"
	"github.com/UpmeshLTD/urus-aio/infrastructure/common"
	"github.com/lib/pq"
	"gorm.io/gorm"
	"gorm.io/gorm/clause"
)

type PaidOrder struct {
	ID                   string `gorm:"default:gen_random_uuid()"`
	WorkspaceID          string
	CartID               string
	ShippingGroupID      *string
	IsFulfilled          *bool          `gorm:"default:true"`
	IsArrangedShip       *bool          `gorm:"default:false"`
	Status               OrderStatus    `gorm:"default:paid"`
	IncorrectInformation pq.StringArray `gorm:"type:text[]"`
	FulfillmentID        *string
	ShipmentID           *string
	Dimension            WeightDimension

	EstimatedFee float64 `gorm:"-:all"`

	AuditTime
	SoftDelete
}

/*--------------------------------------------------------------------------------------------------------------------*/

type WeightDimension struct {
	Weight float64
	Width  *float64
	Length *float64
	Height *float64
}

func (v WeightDimension) Value() (driver.Value, error) {
	return json.Marshal(&v)
}

func (v *WeightDimension) Scan(value interface{}) error {
	return jsonScan(value, v, func() {
		*v = WeightDimension{}
	})
}

/*--------------------------------------------------------------------------------------------------------------------*/

func (v *PaidOrder) BeforeCreate(tx *gorm.DB) (err error) {
	if v.ShippingGroupID == nil || *v.ShippingGroupID == "" {
		emptyShippingGroupID := EmptyShippingGroupID
		v.ShippingGroupID = &emptyShippingGroupID
	}
	tx.Statement.AddClause(clause.OnConflict{
		Columns: []clause.Column{{Name: "id"}},
		DoUpdates: clause.Assignments(map[string]interface{}{
			"cart_id":           v.CartID,
			"shipping_group_id": v.ShippingGroupID,
			"fulfillment_id":    v.FulfillmentID,
		}),
	})
	return nil
}

func (v *PaidOrder) CartShippingGroupKey() string {
	if v.ShippingGroupID == nil || *v.ShippingGroupID == "" {
		return v.CartID + "|-"
	}
	return v.CartID + "|" + *v.ShippingGroupID
}

/*--------------------------------------------------------------------------------------------------------------------*/

type OrderStatus string

const (
	OrderStatusPaid OrderStatus = "paid"
)

func (v OrderStatus) Value() string {
	return string(v)
}

/*--------------------------------------------------------------------------------------------------------------------*/

const (
	IncorrectPickupAddress       = "pickup_address"
	IncorrectDeliveryAddress     = "delivery_address"
	IncorrectDeliveryPhoneNumber = "delivery_phone_number"
)

const EmptyShippingGroupID = "-"

type GetPaidOrdersParams struct {
	IDs             []string
	CartIDs         []string
	FulfillmentIDs  []string
	WorkspaceID     *string
	OnlyDraft       bool
	HasFulfillment  *bool
	HasArrangedShip *bool
	Fields          *[]string
	*common.Pagination
}

type PaidOrderParams struct {
	CartID          string
	ShippingGroupID *string
}

type GetArrangedPaidOrdersParams struct {
	PaidOrders []PaidOrderParams
}

func (p *GetArrangedPaidOrdersParams) ToGetPaidOrdersParams() *GetPaidOrdersParams {
	cartIDs := make([]string, 0)
	for _, po := range p.PaidOrders {
		cartIDs = append(cartIDs, po.CartID)
	}
	return &GetPaidOrdersParams{CartIDs: cartIDs}
}

type GetPaidOrderParams struct {
	ID              string
	CartID          string
	ShippingGroupID *string
}
