package cvt

import (
	"encoding/json"

	apprent "github.com/tidbcloud/devops/entity/approval"
	apprmod "github.com/tidbcloud/devops/models/approval"
	"github.com/tidbcloud/devops/models/base"
	"github.com/tidbcloud/devops/pkg/infra/utils/pointer"
	timeutil "github.com/tidbcloud/devops/pkg/infra/utils/time"
)

type e2m struct{}

func (cvt e2m) Approval(e *apprent.Approval) *apprmod.Approval {
	m := &apprmod.Approval{
		Updatable: base.Updatable{
			Base: base.Base{ID: base.ID(e.ID)},
		},

		Name:          e.Name,
		Applicant:     e.Applicant,
		StartAt:       timeutil.TsToTime(e.StartAt),
		EndAt:         timeutil.TsToTime(e.EndAt),
		Status:        string(e.Status),
		Parameters:    nil,
		Overview:      nil,
		DetailLink:    e.DetailLink,
		Reason:        e.Reason,
		Configuration: nil,
		FromTemplate:  e.FromTemplate,

		Nodes:   make([]*apprmod.ApprovalNode, 0),
		Tasks:   make([]*apprmod.ApprovalTask, 0),
		CCTasks: make([]*apprmod.ApprovalCCTask, 0, len(e.CCTasks)),
	}

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

	for _, apprLevel := range e.Levels {

		for _, node := range apprLevel.Nodes {
			m.Nodes = append(m.Nodes, cvt.ApprovalNode(e.ID, apprLevel.Level, node))

			for _, task := range node.Tasks {
				m.Tasks = append(m.Tasks, cvt.ApprovalTask(e.ID, apprLevel.Level, node.Name, task))
			}
			for _, task := range node.BackupTasks {
				m.Tasks = append(m.Tasks, cvt.ApprovalTask(e.ID, apprLevel.Level, BackupNodeName(node.Name), task))
			}
		}
	}

	for _, cct := range e.CCTasks {
		m.CCTasks = append(m.CCTasks, cvt.CCTask(e.ID, cct))
	}

	for _, at := range e.AdminTasks {
		m.AdminTasks = append(m.AdminTasks, cvt.AdminTask(e.ID, at))
	}

	return m
}

func (cvt e2m) ApprovalNode(apprID uint64, level int, e *apprent.ApprovalNode) *apprmod.ApprovalNode {
	m := &apprmod.ApprovalNode{
		Base: base.Base{
			ID: base.ID(e.ID),
		},

		Name:   e.Name,
		Level:  level,
		Method: string(e.Method),
		Status: string(e.Status),

		ApprovalID: apprID,
	}

	return m
}

func (cvt e2m) ApprovalTask(apprID uint64, level int, nodeName string, e *apprent.ApprovalTask) *apprmod.ApprovalTask {
	var notifyLarkType *string
	if e.NotifyLarkType != nil {
		notifyLarkType = pointer.Pointer(e.NotifyLarkType.String())
	}

	m := &apprmod.ApprovalTask{
		Updatable: base.Updatable{
			Base: base.Base{ID: base.ID(e.ID)},
		},

		Level:           level,
		NodeName:        nodeName,
		User:            e.User,
		StartAt:         timeutil.TsToTime(e.StartAt),
		EndAt:           timeutil.TsToTime(e.EndAt),
		Status:          string(e.Status),
		NotifyMessageID: e.NotifyMessageID,
		NotifyLarkType:  notifyLarkType,

		ApprovalID: apprID,
	}

	return m
}

func (cvt e2m) CCTask(apprID uint64, e *apprent.ApprovalCCTask) *apprmod.ApprovalCCTask {
	m := &apprmod.ApprovalCCTask{
		Base: base.Base{
			ID: base.ID(e.ID),
		},

		User: e.User,

		ApprovalID: apprID,
	}

	return m
}

func (cvt e2m) AdminTask(apprID uint64, e *apprent.ApprovalAdminTask) *apprmod.ApprovalAdminTask {
	m := &apprmod.ApprovalAdminTask{
		Updatable: base.Updatable{
			Base: base.Base{ID: base.ID(e.ID)},
		},

		User:   e.User,
		EndAt:  timeutil.TsToTime(e.EndAt),
		Status: string(e.Status),

		ApprovalID: apprID,
	}

	return m
}
