package action

import (
	"context"
	"errors"
	"fmt"
	"log/slog"
	"strconv"
	"time"

	"github.com/tidbcloud/jiraport/pkg/db"
	"github.com/tidbcloud/jiraport/pkg/entity"
)

type TimeoutCommand struct {
	dbClient db.Interface
	logger   *slog.Logger
}

func NewTimeoutCommand(logger *slog.Logger, dbClient db.Interface) (*TimeoutCommand, error) {
	return &TimeoutCommand{logger: logger, dbClient: dbClient}, nil
}

func (cmd *TimeoutCommand) Exec(ctx context.Context,
	actionExecInfo *entity.NotificationActionExecInfo,
	args ...string,
) (bool, string, error) {
	if len(args) == 0 {
		return false, "", errors.New("timeout function require one parameter")
	}
	dura, err := strconv.Atoi(args[0])
	if err != nil {
		return false, "", fmt.Errorf("parse args error, %w", err)
	}
	if dura <= 0 {
		return false, "", errors.New("bad duration value")
	}

	cmd.logger.Info("timeout action start",
		"issue", actionExecInfo.Notification.IssueKey,
		"duration", dura,
		"args", args)
	ticker := time.NewTicker(2 * time.Second)
	defer ticker.Stop()
	timer := time.NewTimer(time.Duration(dura) * time.Second)
	defer timer.Stop()

	resultChan := make(chan *entity.NotificationActionExecInfo)
	errorChan := make(chan error)

	for {
		select {
		case <-ctx.Done():
			return false, "", errContextDone
		case <-timer.C:
			cmd.logger.Info("timeout action finished",
				"issue", actionExecInfo.Notification.IssueKey)
			return true, "", nil
		case <-ticker.C:
			cmd.logger.Debug("timeout action check",
				"issue", actionExecInfo.Notification.IssueKey)
			go func() {
				currentExecInfo, err := cmd.dbClient.GetNotificationActionExecInfo(actionExecInfo.ID)
				if err != nil {
					errorChan <- err
					return
				}
				resultChan <- currentExecInfo
			}()
		case err := <-errorChan:
			cmd.logger.Error("get action exec info error", "err", err)
		case currentExecInfo := <-resultChan:
			if currentExecInfo.Notification.State != actionExecInfo.Notification.State {
				cmd.logger.Info("notification state changed, stop timeout",
					"issue", actionExecInfo.Notification.IssueKey,
					"current state", currentExecInfo.Notification.State,
					"origin state", actionExecInfo.Notification.State)
				return true, "", nil
			}
		}
	}
}
