package resources

import (
	"time"

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

type ProcessingUsage struct {
	CPUs map[string]*models.CPU `bson:"cpus,omitempty" json:"cpus,omitempty"` // CPUs is the list of CPUs key is model
	GPUs map[string]*models.GPU `bson:"gpus,omitempty" json:"gpus,omitempty"` // GPUs is the list of GPUs key is model
	RAM  *models.RAM            `bson:"ram,omitempty" json:"ram,omitempty"`   // RAM is the RAM

	StorageGb    float64 `bson:"storage,omitempty" json:"storage,omitempty"` // Storage is the storage
	Hypothesis   string  `bson:"hypothesis,omitempty" json:"hypothesis,omitempty"`
	ScalingModel string  `bson:"scaling_model,omitempty" json:"scaling_model,omitempty"` // ScalingModel is the scaling model
}

/*
* ProcessingResource is a struct that represents a processing resource
* it defines the resource processing
 */
type ProcessingResource struct {
	AbstractInstanciatedResource[*ProcessingInstance]
	Infrastructure enum.InfrastructureType `json:"infrastructure" bson:"infrastructure" default:"-1"` // Infrastructure is the infrastructure
	IsService      bool                    `json:"is_service,omitempty" bson:"is_service,omitempty"`  // IsService is a flag that indicates if the processing is a service
	Usage          *ProcessingUsage        `bson:"usage,omitempty" json:"usage,omitempty"`            // Usage is the usage of the processing
	OpenSource     bool                    `json:"open_source" bson:"open_source" default:"false"`
	License        string                  `json:"license,omitempty" bson:"license,omitempty"`
	Maturity       string                  `json:"maturity,omitempty" bson:"maturity,omitempty"`
}

func (r *ProcessingResource) GetType() string {
	return tools.PROCESSING_RESOURCE.String()
}

type ProcessingResourceAccess struct {
	Container *models.Container `json:"container,omitempty" bson:"container,omitempty"` // Container is the container
}

type ProcessingInstance struct {
	ResourceInstance[*ResourcePartnerShip[*ProcessingResourcePricingProfile]]
	Access *ProcessingResourceAccess `json:"access,omitempty" bson:"access,omitempty"` // Access is the access
}

type PricedProcessingResource struct {
	PricedResource
	IsService bool
}

func (r *PricedProcessingResource) GetType() tools.DataType {
	return tools.PROCESSING_RESOURCE
}

func (a *PricedProcessingResource) GetExplicitDurationInS() float64 {
	if a.ExplicitBookingDurationS == 0 {
		if a.IsService || a.UsageStart == nil {
			if a.IsService {
				return -1
			}
			return time.Duration(1 * time.Hour).Seconds()
		}
		return a.UsageEnd.Sub(*a.UsageStart).Seconds()
	}
	return a.ExplicitBookingDurationS
}

func (d *ProcessingResource) GetAccessor(request *tools.APIRequest) utils.Accessor {
	return NewAccessor[*ProcessingResource](tools.PROCESSING_RESOURCE, request, func() utils.DBObject { return &ProcessingResource{} }) // Create a new instance of the accessor
}

type ProcessingResourcePricingProfile struct {
	pricing.AccessPricingProfile[pricing.TimePricingStrategy] // AccessPricingProfile is the pricing profile of a data it means that we can access the data for an amount of time
}

func (p *ProcessingResourcePricingProfile) IsPurchased() bool {
	return p.Pricing.BuyingStrategy != pricing.PAY_PER_USE
}

func (p *ProcessingResourcePricingProfile) GetPrice(amountOfData float64, val float64, start time.Time, end time.Time, params ...string) (float64, error) {
	return p.Pricing.GetPrice(amountOfData, val, start, &end)
}