package cvt

import (
	"encoding/json"
	"time"

	opent "github.com/tidbcloud/devops/entity/operation"
	"github.com/tidbcloud/devops/models/base"
	opmod "github.com/tidbcloud/devops/models/operation"
)

type e2m struct{}

func (cvt e2m) Instance(e *opent.Instance) *opmod.OperationInstance {
	m := &opmod.OperationInstance{
		Updatable: base.Updatable{
			Base: base.Base{ID: base.ID(e.ID)},
		},

		Type:           string(e.Type),
		Operation:      e.Operation,
		Reason:         e.Reason,
		Applicant:      e.Applicant,
		OperatorEntity: e.OperatorEntity,

		ExecutionWindowID: e.ExecutionWindowID,

		Phase:      string(e.Phase),
		ApprovalID: e.ApprovalID,
		ClosedAt:   cvtTsToTime(e.ClosedAt),
	}

	if e.Params != nil {
		data, err := json.Marshal(e.Params)
		if err != nil {
			panic(e)
		}
		m.Params = data
	}

	if e.Outputs != nil {
		data, err := json.Marshal(e.Outputs)
		if err != nil {
			panic(e)
		}
		m.Outputs = data
	}

	for _, action := range e.Actions {
		m.Actions = append(m.Actions, cvt.InstanceAction(e.ID, action))
	}

	// in order to analysis, save the association based on the type
	if tid, is := e.ExistsTargetID(); is && tid != "" {
		m.ToTarget = &opmod.OperationInstanceToTargetMapping{
			InstanceID: e.ID,
			TargetType: string(e.Type),
			TargetID:   tid,
		}
	}

	return m
}

func (cvt e2m) InstanceAction(instanceID uint64, e *opent.InstanceAction) *opmod.OperationInstanceAction {
	m := &opmod.OperationInstanceAction{
		Updatable: base.Updatable{
			Base: base.Base{ID: base.ID(e.ID)},
		},

		Order:           e.Order.Int(),
		Name:            string(e.Name),
		Type:            string(e.Type),
		StartPolicy:     string(e.StartPolicy),
		StartScheduleAt: cvtTsToTime(e.StartScheduleAt),

		StartedAt:  cvtTsToTime(e.StartedAt),
		FinishedAt: cvtTsToTime(e.FinishedAt),
		Status:     string(e.Status),
		Output:     e.Output,

		InstanceID: instanceID,
	}

	return m
}

func cvtTsToTime(ts *int64) *time.Time {
	if ts == nil {
		return nil
	}
	t := time.Unix(*ts, 0)
	return &t
}
