package task

import (
	"context"
	"fmt"
	"strconv"
	"time"

	auditent "github.com/tidbcloud/devops/entity/audit"
	"github.com/tidbcloud/devops/entity/event"
	k8sent "github.com/tidbcloud/devops/entity/k8supgrade"
	"github.com/tidbcloud/devops/pkg/infra/clients/larkcli/notify"
	"github.com/tidbcloud/devops/pkg/infra/consts"
	"github.com/tidbcloud/devops/pkg/infra/log"
	"github.com/tidbcloud/devops/pkg/infra/utils/pointer"
	adsvc "github.com/tidbcloud/devops/pkg/service/audit"
	"github.com/tidbcloud/devops/pkg/service/k8supgrade/task/action"
)

// syncApprovingTask syncs an approving task.
// If the task gets approved, update its status to running, and send a notification.
func (s *svc) syncApprovingTask(ctx context.Context, task *k8sent.Task) {
	logger := log.FromContext(ctx, "func", "syncApprovingTask")

	k8sClusters, err := s.taskRepo.ListK8sClusters(ctx, task.ID, false)
	if err != nil {
		logger.Error(err, "failed to list k8s clusters for task", "task_id", task.ID)
		return
	}

	actor := action.NewK8sUpgradeTaskActor(ctx, s.taskComps(ctx), task)
	if err := s.dbp.Transaction(ctx, func(ctx context.Context) error {
		err := actor.ContinueIfApproved()
		if err != nil {
			return err
		}
		// send the task ID to the syncTasksChan to trigger the syncRunningTask
		s.syncTasksChan <- task.ID
		// record audit log
		_, err = s.buildAndRecordEvent(ctx, actor, event.K8sUpgradeTaskEventTypeFinishApproval)
		if err != nil {
			return err
		}
		logger.Info("task is approved")

		if err = s.larkCli.Notify.SendMessageViaWebhook(ctx, s.conf.LarkWebhook, notify.K8sUpgradeTaskApprovedParam{
			Deadline:      time.Unix(task.Deadline, 0).String(),
			CloudProvider: task.CloudProvider,
			Version:       task.VersionToBeUpgraded,
			NumOfClusters: strconv.Itoa(len(k8sClusters)),
			Detail:        fmt.Sprintf(s.conf.DetailLinkBaseURL, task.ID),
		}); err != nil {
			return fmt.Errorf("send lark message failed: %w", err)
		}
		return nil
	}); err != nil {
		logger.Error(err, "failed to sync approving task")
	}
}

func (s *svc) buildAndRecordEvent(ctx context.Context, actor action.K8sUpgradeTaskActor, typ event.EventType) (*event.K8sUpgradeTaskEvent, error) {
	task := actor.GetContext().Task
	detail := actor.GetContext().EventDetail

	ev := &event.K8sUpgradeTaskEvent{
		BaseEvent: event.BaseEvent{
			ID:            task.ID,
			OperatorEmail: consts.GetOperatorFromCtx(ctx, consts.InternalVirtualEmail),
			OperateAt:     pointer.Pointer(time.Now()),
			EventType:     typ,
		},
	}
	if detail != nil {
		ev.Details = *detail
	}

	auditLog, err := adsvc.EventToAuditLog(ev.BaseEvent, auditent.AuditLogTypeK8sUpgradetask, ev.Details)
	if err != nil {
		return ev, err
	}

	err = s.auditSvc.Create(ctx, auditLog)
	if err != nil {
		return ev, fmt.Errorf("create audit log failed: %w", err)
	}

	return ev, nil
}
