package discount

import (
	"time"

	"cloud.o-forge.io/core/oc-lib/models/utils"
	"cloud.o-forge.io/core/oc-lib/tools"
)

type DiscountType int

const (
	PERCENTAGE   DiscountType = iota // réduction en pourcentage
	FIXED_AMOUNT                     // réduction montant fixe
)

func (d DiscountType) String() string {
	return [...]string{"percentage", "fixed_amount"}[d]
}

func DiscountTypeList() []DiscountType {
	return []DiscountType{PERCENTAGE, FIXED_AMOUNT}
}

type DiscountScope int

const (
	SCOPE_ALL           DiscountScope = iota // applicable à tout
	SCOPE_RESOURCE_TYPE                      // applicable à un type de ressource
	SCOPE_RESOURCE                           // applicable à une ressource spécifique
	SCOPE_SUBSCRIPTION                       // applicable aux souscriptions
)

func (d DiscountScope) String() string {
	return [...]string{"all", "resource_type", "resource", "subscription"}[d]
}

// Discount représente une réduction applicable sur les ressources ou abonnements.
type Discount struct {
	utils.AbstractObject
	Code          string           `json:"code,omitempty" bson:"code,omitempty"`
	DiscountType  DiscountType     `json:"discount_type" bson:"discount_type"`
	Scope         DiscountScope    `json:"scope" bson:"scope"`
	Value         float64          `json:"value" bson:"value"`                                       // pourcentage (0-100) ou montant fixe
	Currency      string           `json:"currency,omitempty" bson:"currency,omitempty"`             // pour FIXED_AMOUNT
	ResourceTypes []tools.DataType `json:"resource_types,omitempty" bson:"resource_types,omitempty"` // si SCOPE_RESOURCE_TYPE
	ResourceIDs   []string         `json:"resource_ids,omitempty" bson:"resource_ids,omitempty"`     // si SCOPE_RESOURCE
	ValidFrom     *time.Time       `json:"valid_from,omitempty" bson:"valid_from,omitempty"`
	ValidUntil    *time.Time       `json:"valid_until,omitempty" bson:"valid_until,omitempty"`
	MaxUsage      int              `json:"max_usage,omitempty" bson:"max_usage,omitempty"` // 0 = illimité
	CurrentUsage  int              `json:"current_usage" bson:"current_usage"`
	MinAmount     float64          `json:"min_amount,omitempty" bson:"min_amount,omitempty"` // montant minimum du bill pour appliquer
	Active        bool             `json:"active" bson:"active" default:"true"`
}

// IsValid vérifie si la réduction est applicable au moment présent.
func (d *Discount) IsValid(billAmount float64) bool {
	now := time.Now().UTC()
	if !d.Active {
		return false
	}
	if d.MaxUsage > 0 && d.CurrentUsage >= d.MaxUsage {
		return false
	}
	if d.ValidFrom != nil && now.Before(*d.ValidFrom) {
		return false
	}
	if d.ValidUntil != nil && now.After(*d.ValidUntil) {
		return false
	}
	if d.MinAmount > 0 && billAmount < d.MinAmount {
		return false
	}
	return true
}

// Apply applique la réduction sur un prix HT et retourne le prix réduit.
func (d *Discount) Apply(priceHT float64) float64 {
	switch d.DiscountType {
	case PERCENTAGE:
		return priceHT - (priceHT * d.Value / 100)
	case FIXED_AMOUNT:
		result := priceHT - d.Value
		if result < 0 {
			return 0
		}
		return result
	}
	return priceHT
}

// DiscountAmount retourne le montant de la réduction sans l'appliquer.
func (d *Discount) DiscountAmount(priceHT float64) float64 {
	switch d.DiscountType {
	case PERCENTAGE:
		return priceHT * d.Value / 100
	case FIXED_AMOUNT:
		if d.Value > priceHT {
			return priceHT
		}
		return d.Value
	}
	return 0
}

// AppliesToResource vérifie si cette réduction s'applique à une ressource donnée.
func (d *Discount) AppliesToResource(resourceID string, resourceType tools.DataType) bool {
	switch d.Scope {
	case SCOPE_ALL:
		return true
	case SCOPE_RESOURCE:
		for _, id := range d.ResourceIDs {
			if id == resourceID {
				return true
			}
		}
	case SCOPE_RESOURCE_TYPE:
		for _, t := range d.ResourceTypes {
			if t == resourceType {
				return true
			}
		}
	}
	return false
}

// IncrementUsage incrémente le compteur d'utilisation.
func (d *Discount) IncrementUsage() {
	d.CurrentUsage++
}

func (d *Discount) GetAccessor(request *tools.APIRequest) utils.Accessor {
	return NewAccessor(request)
}

func (d *Discount) StoreDraftDefault() {
	d.IsDraft = true
}

func (d *Discount) CanUpdate(set utils.DBObject) (bool, utils.DBObject) {
	return d.IsDraft, set
}

func (d *Discount) CanDelete() bool {
	return d.IsDraft || d.CurrentUsage == 0
}
