package kernelimage

import (
	"time"

	"github.com/tidbcloud/devops/api"
	ent "github.com/tidbcloud/devops/entity/kernelimage"
)

type ListReleasesReq struct {
	api.PaginationReq
	Repository string   `form:"repository" json:"repository"`
	Version    string   `form:"version" json:"version"`
	Statuses   []string `form:"statuses" json:"statuses"`
	Masked     *bool    `form:"masked" json:"masked"`
}

type SelectionReq struct {
	ClusterType string `form:"cluster_type" json:"cluster_type" binding:"required"`
	Component   string `form:"component" json:"component" binding:"required"`
}

type Release struct {
	ID                          uint64                      `json:"id"`
	ArtifactUID                 string                      `json:"artifact_uid"`
	LocalDevOpsEnv              string                      `json:"local_devops_environment"`
	Version                     string                      `json:"version"`
	Repo                        string                      `json:"repo"`
	Branch                      string                      `json:"branch"`
	CommitSHA                   string                      `json:"commit_sha"`
	GitTag                      string                      `json:"git_tag"`
	SourceRepository            string                      `json:"source_repository"`
	SourceTag                   string                      `json:"source_tag"`
	SourceDigest                string                      `json:"source_digest"`
	Status                      ent.ReleaseStatus           `json:"status"`
	Masked                      bool                        `json:"masked"`
	MaskReason                  string                      `json:"mask_reason,omitempty"`
	SourceApplicant             string                      `json:"source_applicant"`
	SourceReleaseID             string                      `json:"source_release_id,omitempty"`
	SourceChangeID              string                      `json:"source_change_id,omitempty"`
	DeliveryOperationInstanceID *uint64                     `json:"delivery_operation_instance_id,omitempty"`
	FormalDeliveryUID           string                      `json:"formal_delivery_uid"`
	DeliveryBatchUID            string                      `json:"delivery_batch_uid"`
	DeliveryTargetImages        []string                    `json:"delivery_target_images,omitempty"`
	AvailabilityStatus          ent.AvailabilityStatus      `json:"availability_status"`
	Availability                []*ent.PlatformAvailability `json:"availability,omitempty"`
	AvailabilityCheckUID        string                      `json:"availability_check_uid,omitempty"`
	AvailabilityCheckStartedAt  *time.Time                  `json:"availability_check_started_at,omitempty"`
	AvailabilityCheckedAt       *time.Time                  `json:"availability_checked_at,omitempty"`
	AvailabilityLastError       string                      `json:"availability_last_error,omitempty"`
	LastErrorCode               string                      `json:"last_error_code,omitempty"`
	LastErrorMessage            string                      `json:"last_error_message,omitempty"`
	BuildFinishedAt             *time.Time                  `json:"build_finished_at,omitempty"`
	AvailableAt                 *time.Time                  `json:"available_at,omitempty"`
	CreatedAt                   time.Time                   `json:"created_at"`
	UpdatedAt                   *time.Time                  `json:"updated_at,omitempty"`
}

type ListReleasesResp struct {
	api.BaseResp `json:",inline"`
	Total        int64      `json:"total"`
	Items        []*Release `json:"items"`
}

type GetReleaseResp struct {
	api.BaseResp `json:",inline"`
	Release      *Release `json:"release"`
}

type SelectionPolicy struct {
	VersionCount           int    `json:"version_count"`
	ImageTagCount          int    `json:"image_tag_count"`
	LocalDevOpsEnvironment string `json:"local_devops_environment"`
}

type SelectionItem struct {
	Release         *Release            `json:"release"`
	IsDefault       bool                `json:"is_default"`
	SelectionState  ent.SelectionState  `json:"selection_state"`
	ExclusionReason ent.ExclusionReason `json:"exclusion_reason,omitempty"`
}

type SelectionVersion struct {
	Version string           `json:"version"`
	Images  []*SelectionItem `json:"images"`
}

type SelectionResp struct {
	api.BaseResp `json:",inline"`
	Policy       SelectionPolicy     `json:"policy"`
	CalculatedAt time.Time           `json:"calculated_at"`
	Versions     []*SelectionVersion `json:"versions"`
	Excluded     []*SelectionItem    `json:"excluded"`
}

func NewRelease(release *ent.Release) *Release {
	if release == nil {
		return nil
	}
	result := &Release{
		ID: release.ID, ArtifactUID: release.ArtifactUID, LocalDevOpsEnv: release.LocalDevOpsEnv,
		Version: release.Version,
		Repo:    release.Repo, Branch: release.Branch,
		CommitSHA: release.CommitSHA, GitTag: release.GitTag, SourceRepository: release.SourceRepository,
		SourceTag: release.SourceTag, SourceDigest: release.SourceDigest, Status: release.Status,
		Masked: release.Masked, MaskReason: release.MaskReason, SourceApplicant: release.SourceApplicant,
		SourceReleaseID: release.SourceReleaseID, SourceChangeID: release.SourceChangeID,
		DeliveryOperationInstanceID: release.DeliveryOperationInstanceID,
		FormalDeliveryUID:           release.FormalDeliveryUID,
		DeliveryBatchUID:            release.DeliveryBatchUID,
		DeliveryTargetImages:        release.DeliveryTargetImages,
		AvailabilityStatus:          release.AvailabilityStatus,
		Availability:                release.Availability,
		AvailabilityCheckUID:        release.AvailabilityCheckUID,
		AvailabilityCheckStartedAt:  release.AvailabilityCheckStartedAt,
		AvailabilityCheckedAt:       release.AvailabilityCheckedAt,
		AvailabilityLastError:       release.AvailabilityLastError,
		LastErrorCode:               release.LastErrorCode, LastErrorMessage: release.LastErrorMessage,
		BuildFinishedAt: release.BuildFinishedAt, AvailableAt: release.AvailableAt,
		CreatedAt: release.CreatedAt, UpdatedAt: release.UpdatedAt,
	}
	return result
}

func NewSelection(result *ent.SelectionResult) *SelectionResp {
	response := &SelectionResp{
		Policy: SelectionPolicy{
			VersionCount: result.Policy.VersionCount, ImageTagCount: result.Policy.ImageTagCount,
			LocalDevOpsEnvironment: result.Policy.LocalDevOpsEnvironment,
		},
		CalculatedAt: result.CalculatedAt,
		Versions:     make([]*SelectionVersion, 0, len(result.Versions)),
		Excluded:     make([]*SelectionItem, 0, len(result.Excluded)),
	}
	for _, version := range result.Versions {
		converted := &SelectionVersion{Version: version.Version, Images: make([]*SelectionItem, 0, len(version.Images))}
		for _, item := range version.Images {
			converted.Images = append(converted.Images, newSelectionItem(item))
		}
		response.Versions = append(response.Versions, converted)
	}
	for _, item := range result.Excluded {
		response.Excluded = append(response.Excluded, newSelectionItem(item))
	}
	return response
}

func newSelectionItem(item *ent.SelectionItem) *SelectionItem {
	return &SelectionItem{
		Release: NewRelease(item.Release), IsDefault: item.IsDefault,
		SelectionState: item.SelectionState, ExclusionReason: item.ExclusionReason,
	}
}
