package pricing

import (
	"time"
)

type PricingProfileITF interface {
	IsBooked() bool
	IsPurchasable() bool
	GetPurchase() BuyingStrategy
	GetOverrideStrategyValue() int
	GetPriceHT(quantity float64, val float64, start time.Time, end time.Time, variation []*PricingVariation, params ...string) (float64, error)
}

type RefundType int

const (
	REFUND_DEAD_END RefundType = iota
	REFUND_ON_ERROR
	REFUND_ON_EARLY_END
)

func (t RefundType) String() string {
	return [...]string{"REFUND ON DEAD END", "REFUND ON ERROR", "REFUND ON EARLY END"}[t]
}

func RefundTypeList() []RefundType {
	return []RefundType{REFUND_DEAD_END, REFUND_ON_ERROR, REFUND_ON_EARLY_END}
}

type PaymentType int

const (
	PAY_ONCE PaymentType = iota
	PAY_EVERY_WEEK
	PAY_EVERY_MONTH
	PAY_EVERY_YEAR
)

func (t PaymentType) String() string {
	return [...]string{"PAY ONCE", "PAY_EVERY_WEEK", "PAY_EVERY_MONTH", "PAY_EVERY_YEAR"}[t]
}

func PaymentTypeList() []PaymentType {
	return []PaymentType{PAY_ONCE, PAY_EVERY_WEEK, PAY_EVERY_MONTH, PAY_EVERY_YEAR}
}

type AccessPricingProfile[T Strategy] struct { // only use for acces such as : DATA && PROCESSING
	AllowedPaymentType []PaymentType      `json:"allowed_payment_type,omitempty" bson:"allowed_payment_type,omitempty"` // Price is the price of the resource
	Pricing            PricingStrategy[T] `json:"pricing,omitempty" bson:"pricing,omitempty"`                           // Price is the price of the resource
	DefaultRefund      RefundType         `json:"default_refund" bson:"default_refund"`                                 // DefaultRefund is the default refund type of the pricing
	RefundRatio        int32              `json:"refund_ratio" bson:"refund_ratio" default:"0"`                         // RefundRatio is the refund ratio if missing
}

func (a AccessPricingProfile[T]) IsBooked() bool {
	return a.Pricing.BuyingStrategy == SUBSCRIPTION
}

func (a AccessPricingProfile[T]) IsPurchasable() bool {
	return a.Pricing.BuyingStrategy == PERMANENT
}

func (a AccessPricingProfile[T]) GetPurchase() BuyingStrategy {
	return a.Pricing.BuyingStrategy
}

func (a AccessPricingProfile[T]) GetPriceHT(quantity float64, val float64, start time.Time, end time.Time, variations []*PricingVariation, params ...string) (float64, error) {
	return a.Pricing.GetPriceHT(quantity, val, start, &end, variations)
}

func (b *AccessPricingProfile[T]) GetOverrideStrategyValue() int {
	return -1
}

func GetDefaultPricingProfile() PricingProfileITF {
	return &AccessPricingProfile[TimePricingStrategy]{
		Pricing: PricingStrategy[TimePricingStrategy]{
			Price:               0,
			Currency:            "EUR",
			BuyingStrategy:      SUBSCRIPTION,
			TimePricingStrategy: PER_SECOND,
		},
	}
}

type ExploitPrivilegeStrategy int

const (
	BASIC ExploitPrivilegeStrategy = iota
	GARANTED_ON_DELAY
	GARANTED
)

func ExploitPrivilegeStrategyList() []ExploitPrivilegeStrategy {
	return []ExploitPrivilegeStrategy{BASIC, GARANTED_ON_DELAY, GARANTED}
}

func (t ExploitPrivilegeStrategy) String() string {
	return [...]string{"NO GARANTY", "GARANTED ON SPECIFIC DELAY", "GARANTED"}[t]
}

type ExploitPricingProfile[T Strategy] struct { // only use for exploit such as : STORAGE, COMPUTE, WORKFLOW
	AccessPricingProfile[T]
	AdditionnalRefundTypes []RefundType `json:"refund_types" bson:"refund_types"` // RefundTypes is the refund types of the pricing

	PrivilegeStrategy   ExploitPrivilegeStrategy `json:"privilege_strategy,omitempty" bson:"privilege_strategy,omitempty"`       // Strategy is the strategy of the pricing
	GarantedDelaySecond uint                     `json:"garanted_delay_second,omitempty" bson:"garanted_delay_second,omitempty"` // GarantedDelaySecond is the garanted delay of the pricing

	Exceeding      bool  `json:"exceeding" bson:"exceeding"`                         // Exceeding is the exceeding of the bill
	ExceedingRatio int32 `json:"exceeding_ratio" bson:"exceeding_ratio" default:"0"` // ExceedingRatio is the exceeding ratio of the bill
}
