package entity

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

	"gorm.io/gorm"
)

type (
	// uint64 ID for all tables
	ID uint64
	// base
	Base struct {
		ID        ID        `gorm:"primary_key;not null"`
		CreatedAt time.Time `gorm:"created_at;type:TIMESTAMP;not null;<-:create"` // create and read only
	}
	Versioned struct {
		Versioning int `gorm:"versioning; default:1"`
	}

	// Updatable table
	Updatable struct {
		Base
		UpdatedAt *time.Time `gorm:"updated_at;type:TIMESTAMP"`
	}

	Integration struct {
		Updatable
		TenantID                ID                           `gorm:"uniqueIndex:idx_project_type;not null"`
		ProjectID               ID                           `gorm:"uniqueIndex:idx_project_type;not null"`
		ClusterID               ID                           `gorm:"uniqueIndex:idx_project_type;not null"`
		Region                  string                       `gorm:"type:VARCHAR(64);uniqueIndex:idx_project_type;not null"`
		CloudProviderType       IntegrationCloudProviderType `gorm:"type:enum('UNSPECIFIED','AWS','GCP','AZURE','LOCAL','ALIBABACLOUD');not null"`
		ProviderType            IntegrationType              `gorm:"type:ENUM('UNSPECIFIED','DATADOG','PROMETHEUS','NEWRELIC');uniqueIndex:idx_project_type;not null;default:'UNSPECIFIED'"`
		Status                  IntegrationStatus            `gorm:"type:ENUM('UNSPECIFIED','NONE','ACTIVE','ERROR');not null;default:'UNSPECIFIED'"`
		StatusReason            string                       `gorm:"type:VARCHAR(1024)"`
		Payloads                IntegrationPayloads          `gorm:"type:JSON"`
		DatadogSite             DatadogSite                  `gorm:"type:ENUM('UNSPECIFIED','US1','US3','US5','EU1','US1_FED','AP1')"`
		MaskedDatadogApiKey     string                       `gorm:"type:VARCHAR(128)"`
		EncryptedDatadogApiKey  string                       `gorm:"type:VARCHAR(1024)"`
		NewrelicSite            NewrelicSite                 `gorm:"type:ENUM('UNSPECIFIED','US_OTLP','EU_OTLP');default:'UNSPECIFIED'"`
		MaskedNewrelicApiKey    string                       `gorm:"type:VARCHAR(128)"`
		EncryptedNewrelicApiKey string                       `gorm:"type:VARCHAR(1024)"`
		DeletedAt               gorm.DeletedAt               `gorm:"deleted_at;type:TIMESTAMP;uniqueIndex:idx_project_type"` // soft delete
	}
)

func (Integration) TableName() string {
	return "integrations_v2"
}

func (u *Base) GetID() ID {
	return u.ID
}

func (u *Versioned) GetVersioning() int {
	return u.Versioning
}

func (u *Versioned) BeforeUpdate(tx *gorm.DB) (err error) {
	// should go here if we use db.Save(model)/db.Updates(model)
	if u.Versioning != 0 {
		tx.Statement.SetColumn("versioning", u.Versioning+1)
	} else { // should go here if we use db.Update(k,v)/db.Updates(map)
		tx.Statement.SetColumn("versioning", gorm.Expr("versioning + 1"))
	}
	return nil
}

type IntegrationPayloads struct {
	Payloads []IntegrationPayload `json:"payloads"`
}

func (p IntegrationPayloads) Value() (driver.Value, error) {
	b, err := json.Marshal(p)
	return string(b), err
}

func (p *IntegrationPayloads) Scan(input interface{}) error {
	return json.Unmarshal(input.([]byte), p)
}

func (site DatadogSite) GetDatadogSiteUrl() string {
	// DatadogSiteUrl refers to [https://github.com/DataDog/datadog-agent/blob/main/pkg/config/config_template.yaml]
	switch site {
	case DatadogSiteUS1:
		return "datadoghq.com"
	case DatadogSiteUS3:
		return "us3.datadoghq.com"
	case DatadogSiteUS5:
		return "us5.datadoghq.com"
	case DatadogSiteEU1:
		return "datadoghq.eu"
	case DatadogSiteUS1FED:
		return "ddog-gov.com"
	case DatadogSiteAP1:
		return "ap1.datadoghq.com"
	default:
		return "datadoghq.com"
	}
}
