package k8supgrade

import (
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
)

type Task struct {
	ID                  uint64           `json:"id"`
	Name                string           `json:"name"`
	CloudProvider       string           `json:"cloud_provider"`
	K8sClusterList      []*K8sCluster    `json:"k8s_cluster_list"`
	ExcludedK8sClusters []*K8sCluster    `json:"excluded_k8s_clusters"`
	VersionToBeUpgraded string           `json:"version_to_be_upgraded"`
	MaxRestartTimes     uint32           `json:"max_restart_times"`
	Deadline            int64            `json:"deadline"`
	CreatedAt           int64            `json:"created_at"`
	ClosedAt            *int64           `json:"closed_at"`
	Applicant           string           `json:"applicant"` // email
	ApprovalID          *uint64          `json:"approval_id"`
	Status              TaskStatus       `json:"status"`
	Regions             map[string]int64 `json:"regions"`
	// Synced indicates whether the task has been synced.
	// This field is only used for the task in pending phase.
	Synced bool `json:"synced"`

	// SelectorType indicates the mutually exclusive selector type.
	SelectorType  string `json:"selector_type"`
	SelectorValue string `json:"selector_value"`
} // @name k8supgrade.Task

// ReadOnlyTask is the interface for read-only task.
type ReadOnlyTask interface {
	ID() uint64
	Deadline() int64
	MaxRestartTimes() uint32
}

type readOnlyTask struct {
	id              uint64
	maxRestartTimes uint32
	deadline        int64
}

func (r *readOnlyTask) ID() uint64 {
	return r.id
}

func (r *readOnlyTask) Deadline() int64 {
	return r.deadline
}

func (r *readOnlyTask) MaxRestartTimes() uint32 {
	return r.maxRestartTimes
}

var _ ReadOnlyTask = &readOnlyTask{}

func NewReadOnlyTask(task *Task) ReadOnlyTask {
	return &readOnlyTask{
		id:              task.ID,
		maxRestartTimes: task.MaxRestartTimes,
		deadline:        task.Deadline,
	}
}

type TaskStatus string

const (
	TaskStatusPending   TaskStatus = "pending"
	TaskStatusApproving TaskStatus = "approving"
	TaskStatusRunning   TaskStatus = "running"
	TaskStatusCompleted TaskStatus = "completed"
	TaskStatusCancelled TaskStatus = "cancelled"
)

type K8sCluster struct {
	ID         uint64 `json:"id"`
	Name       string `json:"name"`
	TaskID     uint64 `json:"task_id"`
	TenantName string `json:"tenant_name"`
	TenantKind string `json:"tenant_kind"`
	// SalesOwnerEmail and TAMName are resolved from tenant service at read time.
	SalesOwnerEmail        string  `json:"sales_owner_email"`
	TAMName                string  `json:"tam_name"`
	Region                 string  `json:"region"`
	BusinessRegion         string  `json:"business_region"`
	CloudProvider          string  `json:"cloud_provider"`
	MaintenanceWindowID    *uint64 `json:"maintenance_window_id"`
	UpgradeOperationStatus string  `json:"upgrade_operation_status"`
	UpgradeOperationCR     string  `json:"upgrade_operation_cr"`
	IsExcluded             bool    `json:"is_excluded"`
	DesiredVersion         string  `json:"desired_version"`
	// DisableAutoGeneration indicates whether to disable auto generation for the UpgradeOperationCR.
	DisableAutoGeneration bool `json:"disable_auto_generation"`
	// K8sSnapshot is a snapshot of the K8s cluster before the task starts running.
	// It's used to record the initial state of the cluster.
	K8sSnapshot *K8sInfo `json:"k8s_snapshot"`
	// Info contains the information of the K8s cluster.
	// It will not be stored in the database.
	// It represents the latest state of the cluster.
	Info *K8sInfo `json:"info"`
	// Version is used for optimistic locking. See models/k8supgrade.K8sCluster.Version.
	Version uint64 `json:"version"`
} // @name k8supgrade.K8sCluster

const (
	UOStatusCancelled = "cancelled"
)

// Signature returns a hex-encoded SHA-256 hash of every field that
// will be written to the database by the repo layer.
func (c *K8sCluster) Signature() string {

	var (
		data []byte
		err  error
	)

	if c.Info != nil {
		cp := *c
		// Normalize Info → K8sSnapshot, mirroring entity_to_model.go:
		//   Info (live state) takes priority over K8sSnapshot (previously stored).
		if cp.Info != nil {
			cp.K8sSnapshot = cp.Info
		}
		cp.Info = nil // transient field; not stored directly in DB
		data, err = json.Marshal(cp)
	} else {
		data, err = json.Marshal(c)
	}

	if err != nil {
		panic("k8supgrade: Signature marshal failed: " + err.Error())
	}
	sum := sha256.Sum256(data)
	return hex.EncodeToString(sum[:])
}
