package action

import (
	"context"
	"errors"
	"fmt"
	"math/rand"

	"github.com/spf13/viper"
	"gorm.io/gorm"

	eng "jiraport/resolver/engineer"
	"jiraport/service/jira"
	ntf "jiraport/service/notification"
)

type EscalateCommand struct {
	db         *gorm.DB
	jira       *jira.Jira
	ns         *ntf.Notifications
	needAssign bool
}

func NewEscalateCommand(db *gorm.DB, jira *jira.Jira, ns *ntf.Notifications) (*EscalateCommand, error) {

	needAssign := viper.GetBool("need-assign")

	return &EscalateCommand{
		db:         db,
		jira:       jira,
		ns:         ns,
		needAssign: needAssign,
	}, nil
}

func (cmd *EscalateCommand) selectEscalationEngineer(engineers []eng.Engineer) (*eng.Engineer, error) {
	if len(engineers) == 0 {
		return nil, errors.New("empty escalation engineers to select")
	}
	return &engineers[rand.Intn(len(engineers))], nil
}

func (cmd *EscalateCommand) escalate(issue *jira.Issue) (*eng.Engineer, error) {
	assigneeEmail := issue.AssigneeEmail

	if assigneeEmail == "" {
		return nil, errors.New("no assignee for escalation")
	}

	engineers, err := eng.GetEscalationChainEngineerByAssigneeEmail(cmd.db, assigneeEmail)
	if err != nil {
		return nil, err
	}

	engineer, err := cmd.selectEscalationEngineer(engineers)
	if err != nil {
		return nil, err
	}

	err = cmd.jira.Assign(issue.Key, engineer.Email)
	if err != nil {
		return nil, fmt.Errorf("assign error %w", err)
	}
	return engineer, nil
}

func (cmd *EscalateCommand) Exec(ctx context.Context, actionExecInfo *ntf.NotificationActionExecInfo, args ...string) (bool, error) {
	if !cmd.needAssign {
		return false, errors.New("\"need-assign\" is not set, action is not allowed")
	}

	issue := actionExecInfo.Notification.Issue

	assignee, err := cmd.escalate(issue)
	if err != nil {
		return false, err
	}

	err = cmd.ns.UpdateAssignee(issue.Key, assignee.Email)
	if err != nil {
		return false, err
	}

	return true, nil
}
