package cvt

import (
	"encoding/json"
	"fmt"

	ccent "github.com/tidbcloud/devops/entity/cloudconfig"
	ccmod "github.com/tidbcloud/devops/models/cloudconfig"
	"github.com/tidbcloud/devops/pkg/infra/utils/container"
	timeutil "github.com/tidbcloud/devops/pkg/infra/utils/time"
)

type m2e struct{}

func (cvt m2e) ConfigurationChange(m *ccmod.ConfigurationChange) *ccent.ConfigurationChange {
	e := &ccent.ConfigurationChange{
		ID:             m.ID.Uint64(),
		TargetType:     ccent.ConfigurationChangeTargetType(m.TargetType),
		TargetVersion:  m.TargetVersion,
		ChangeType:     m.ChangeType,
		Reason:         m.Reason,
		Applicant:      m.Applicant,
		OperatorEntity: m.OperatorEntity,
		ApplyPolicy:    ccent.ParameterApplyPolicy(m.ApplyPolicy),

		Phase:      ccent.ConfigurationChangePhase(m.Phase),
		ApprovalID: m.ApprovalID,
		CreatedAt:  m.CreatedAt.Unix(),
		ClosedAt:   timeutil.TimeToTs(m.ClosedAt),
		AppliedAt:  timeutil.TimeToTs(m.AppliedAt),

		ExecutionWindowID: m.ExecutionWindowID,

		PremiumUpgradeStepID: m.PremiumUpgradeStepID,
	}

	for _, file := range m.Files {
		e.Scope.Files = append(e.Scope.Files, cvt.ConfigurationFileChange(file))
	}
	for _, comp := range m.Components {
		e.Scope.Components = append(e.Scope.Components, cvt.ConfigurationComponentChange(comp))
	}
	if m.Version != nil {
		e.Scope.Version = cvt.ConfigurationVersionChange(m.Version)
	}
	if m.ToCluster != nil {
		e.TargetCluster = &ccent.ClusterConfigurationLocator{
			ClusterType: ccent.ClusterType(m.ToCluster.ClusterType),
			ClusterID:   m.ToCluster.ClusterID,
		}
	}
	if m.ToTenantInit != nil {
		e.TargetTenantInit = &ccent.TenantInitConfigurationLocator{
			ClusterType: ccent.ClusterType(m.ToTenantInit.ClusterType),
			TenantID:    m.ToTenantInit.TenantID,
		}
	}
	if m.ToTemplate != nil {
		e.TargetTemplate = &ccent.ConfigurationTemplateLocator{
			ClusterType:  ccent.ClusterType(m.ToTemplate.ClusterType),
			TemplateType: ccent.TemplateType(m.ToTemplate.TemplateType),
			TenantID:     m.ToTemplate.TenantID,
		}
	}

	return e
}
func (cvt m2e) ConfigurationFileChange(m *ccmod.ConfigurationFileChange) *ccent.ConfigurationFileChange {
	var err error

	e := &ccent.ConfigurationFileChange{
		ID:                m.ID.Uint64(),
		TemplateID:        m.TemplateID,
		Filename:          m.Filename,
		ConfigType:        m.ConfigType,
		PreviousText:      m.PreviousText,
		ClearCustomParams: m.ClearCustomParams,
	}

	ccfg := []ccent.UsedParameter{}
	err = json.Unmarshal(m.AllParameters, &ccfg)
	if err != nil {
		panic(fmt.Errorf("failed to unmarshal custom configs: %v", err))
	}
	e.AllParameters = ccfg

	if len(m.ModifiedParameters) != 0 {
		mcfg := []ccent.ChangedParameter{}
		err = json.Unmarshal(m.ModifiedParameters, &mcfg)
		if err != nil {
			panic(fmt.Errorf("failed to unmarshal modified configs: %v", err))
		}
		e.ModifiedParameters = mcfg
	}

	if len(m.ModifiedTemplate) != 0 {
		mtmpl := &ccent.ChangedTemplate{}
		err = json.Unmarshal(m.ModifiedTemplate, mtmpl)
		if err != nil {
			panic(fmt.Errorf("failed to unmarshal modified template: %v", err))
		}
		e.ModifiedTemplate = mtmpl
	}

	return e
}

func (cvt m2e) ConfigurationComponentChange(m *ccmod.ConfigurationComponentChange) *ccent.ConfigurationComponentChange {
	var err error

	e := &ccent.ConfigurationComponentChange{
		ID:        m.ID.Uint64(),
		Component: m.Component,
	}

	if len(m.ModifiedImageTag) != 0 {
		modif := &ccent.ChangedImageTag{}
		err = json.Unmarshal(m.ModifiedImageTag, modif)
		if err != nil {
			panic(fmt.Errorf("failed to unmarshal modified image tag: %v", err))
		}
		e.ModifiedImageTag = modif
	}

	if len(m.ModifiedVersion) != 0 {
		modif := &ccent.ChangedVersion{}
		err = json.Unmarshal(m.ModifiedVersion, modif)
		if err != nil {
			panic(fmt.Errorf("failed to unmarshal modified version: %v", err))
		}
		e.ModifiedVersion = modif
	}

	if len(m.ModifiedOverwriteImageTag) != 0 {
		modif := &ccent.ChangedImageTag{}
		err = json.Unmarshal(m.ModifiedOverwriteImageTag, modif)
		if err != nil {
			panic(fmt.Errorf("failed to unmarshal modified image tag: %v", err))
		}
		e.ModifiedOverwriteImageTag = modif
	}

	return e
}

func (cvt m2e) ConfigurationVersionChange(m *ccmod.ConfigurationVersionChange) *ccent.ConfigurationVersionChange {
	e := &ccent.ConfigurationVersionChange{
		ID:   m.ID.Uint64(),
		From: m.FromVersion,
		To:   m.ToVersion,
	}
	return e
}

func (cvt m2e) DefaultConfigurationChange(m *ccmod.DefaultConfigurationChange) *ccent.DefaultConfigurationChange {
	e := &ccent.DefaultConfigurationChange{
		ID:           m.ID.Uint64(),
		CreatedAt:    m.CreatedAt.Unix(),
		ClosedAt:     timeutil.TimeToTs(m.ClosedAt),
		Applicant:    m.Applicant,
		Reason:       m.Reason,
		DisplayName:  m.DisplayName,
		Phase:        ccent.DefaultConfigurationChangePhase(m.Phase),
		PhaseReason:  m.PhaseReason,
		ItemTypes:    container.TransformSlice(m.ItemTypes, container.FromString[ccent.DefaultConfigurationChangeItemType]),
		Environments: m.Environments,
	}

	return e
}

func (cvt m2e) DefaultConfigurationChangeRelease(m *ccmod.DefaultConfigurationChangeRelease) *ccent.DefaultConfigurationChangeRelease {
	e := &ccent.DefaultConfigurationChangeRelease{
		ID:            m.ID.Uint64(),
		Environment:   m.Environment,
		Description:   m.Description,
		ReleasedAt:    timeutil.TimeToTs(m.ReleasedAt),
		ReleaseNumber: m.ReleaseNumber,
		Phase:         ccent.DefaultConfigurationChangeReleasePhase(m.Phase),
		ApprovalID:    m.ApprovalID,
		ParentID:      m.ParentID,
	}

	return e
}

func (cvt m2e) DefaultConfigurationChangeItem(m *ccmod.DefaultConfigurationChangeItem) *ccent.DefaultConfigurationChangeItem {
	e := &ccent.DefaultConfigurationChangeItem{
		ID:       m.ID.Uint64(),
		ItemType: ccent.DefaultConfigurationChangeItemType(m.ItemType),
		ParentID: m.ParentID,
	}

	if len(m.Data) != 0 {
		union := &ccent.DefaultConfigurationChangeItemDataUnion{}
		err := json.Unmarshal(m.Data, &union)
		if err != nil {
			panic(fmt.Errorf("failed to unmarshal modified data: %v", err))
		}
		e.Data = union
	}

	return e
}

func (cvt m2e) DefaultConfigurationChangeItemRelease(m *ccmod.DefaultConfigurationChangeItemRelease) *ccent.DefaultConfigurationChangeItemRelease {
	e := &ccent.DefaultConfigurationChangeItemRelease{
		ID:            m.ID.Uint64(),
		Environment:   m.Environment,
		ItemID:        m.ItemID,
		ReleaseNumber: m.ReleaseNumber,
		ParentID:      m.ParentID,
	}

	if len(m.Data) != 0 {
		union := &ccent.DefaultConfigurationChangeItemReleaseDataUnion{}
		err := json.Unmarshal(m.Data, &union)
		if err != nil {
			panic(fmt.Errorf("failed to unmarshal modified data: %v", err))
		}
		e.Data = union
	}

	return e
}
