package release

import (
	"time"

	"github.com/tidbcloud/devops/models/base"
	"gorm.io/gorm"
)

type (
	ChangeStatus       string
	ChangeResult       string
	ChangeType         string
	RiskLevel          string
	ChangeDeployMethod string
	ChangeDeployStatus string
)

// Enums
const (
	ChangeStatusDraft         ChangeStatus = "draft"
	ChangeStatusCreated       ChangeStatus = "created"
	ChangeStatusApproving     ChangeStatus = "approving"
	ChangeStatusWaitForDeploy ChangeStatus = "wait_for_deploy"
	ChangeStatusInProgress    ChangeStatus = "in_progress"
	ChangeStatusObserving     ChangeStatus = "observing"
	ChangeStatusClosed        ChangeStatus = "closed"
	ChangeStatusWithdrawn     ChangeStatus = "withdrawn"

	ChangeResultCancel          ChangeResult = "cancel"
	ChangeResultSuccessful      ChangeResult = "successful"
	ChangeResultFailed          ChangeResult = "failed"
	ChangeResultFailedPartially ChangeResult = "failed_partially"
	ChangeResultRollback        ChangeResult = "rollback"

	ChangeTypeSprint ChangeType = "sprint"
	ChangeTypeHotfix ChangeType = "hotfix"

	RiskLevelLow    RiskLevel = "low"
	RiskLevelMedium RiskLevel = "medium"
	RiskLevelHigh   RiskLevel = "high"

	ChangeDeployMethodArgoCD ChangeDeployMethod = "argocd"
	ChangeDeployMethodManual ChangeDeployMethod = "manual"

	ChangeDeployStatusCreated  ChangeDeployStatus = "created"
	ChangeDeployStatusDeployed ChangeDeployStatus = "deployed"
	ChangeDeployStatusVerified ChangeDeployStatus = "verified"
)

type Change struct {
	base.Updatable

	Name            string        `gorm:"type:VARCHAR(255);not null"`
	WindowStartAt   time.Time     `gorm:"type:TIMESTAMP;not null"`
	WindowEndAt     time.Time     `gorm:"type:TIMESTAMP;not null"`
	ClosedAt        *time.Time    `gorm:"type:TIMESTAMP"`
	Tier            string        `gorm:"type:VARCHAR(255);not null"` // use ',' to split
	RiskLevel       RiskLevel     `gorm:"type:ENUM('low', 'medium', 'high');not null"`
	ChangeItemNames string        `gorm:"type:VARCHAR(255);"` // release ticket names, use ',' to split
	Status          ChangeStatus  `gorm:"type:ENUM('draft', 'created', 'approving', 'wait_for_deploy', 'in_progress', 'observing', 'closed', 'withdrawn');index:idx_phase;not null"`
	StatusReason    string        `gorm:"type:VARCHAR(512);"`
	Result          *ChangeResult `gorm:"type:ENUM('cancel', 'successful', 'failed', 'failed_partially', 'rollback')"`
	Type            ChangeType    `gorm:"type:ENUM('sprint', 'hotfix');not null"`

	Detail       *ChangeDetail       `gorm:"foreignkey:ChangeID"` // TODO: rename to detail
	Deployments  []*ChangeDeployment `gorm:"foreignkey:ChangeID"`
	Notification *ChangeNotification `gorm:"foreignkey:ChangeID"`

	ReleaseID       base.ID  `gorm:"index:idx_release_id;not null"`
	ApplicantEmail  string   `gorm:"type:VARCHAR(255);not null"`
	ApplicationName string   `gorm:"type:VARCHAR(255);index:idx_application_name;not null"`
	ApprovalID      *base.ID `gorm:"index:idx_approval_id"`
	PrevApprovalIDs string   `gorm:"type:VARCHAR(255)"` // use ',' to split
}

func (Change) TableName() string {
	return "release_changes"
}

type ChangeDetail struct {
	base.Updatable

	ChangeID base.ID `gorm:"uniqueIndex:idx_change_id;not null"`

	NeedOutage        bool    `gorm:"default:false;not null"`
	Note              string  `gorm:"type:TEXT"`
	RollbackPlan      string  `gorm:"type:TEXT"`
	StagingTestReport string  `json:"type:TEXT"`
	Summary           *string `gorm:"type:TEXT"`
}

func (ChangeDetail) TableName() string {
	return "release_change_details"
}

type ChangeNotification struct {
	base.Updatable

	ChangeID base.ID `gorm:"index:idx_change_id;not null"`

	LarkTopicCreatedAt *time.Time `gorm:"type:TIMESTAMP"`
	LarkTopicID        *string    `gorm:"type:VARCHAR(255)"`
	NotifiedToCloseAt  *time.Time `gorm:"type:TIMESTAMP"`
}

func (ChangeNotification) TableName() string {
	return "release_change_notifications"
}

type ChangeDeployment struct {
	base.Updatable
	DeletedAt gorm.DeletedAt

	ChangeID base.ID `gorm:"index:idx_change_id;not null"`

	Order      int                `gorm:"not null"`
	Regions    string             `gorm:"type:VARCHAR(1024);not null"` // use ',' to split
	DeployedAt *time.Time         `gorm:"type:TIMESTAMP"`
	Status     ChangeDeployStatus `gorm:"type:ENUM('created', 'deployed', 'verified');not null"`
	Method     ChangeDeployMethod `gorm:"type:ENUM('argocd', 'manual', 'ee_api');not null"`
	Info       []byte             `gorm:"type:JSON"`
	Note       string             `gorm:"type:VARCHAR(1024)"`
}

func (ChangeDeployment) TableName() string {
	return "release_change_deployments"
}

// TODO: ChangeStat
