package m2mcore

import (
	"errors"
	"fmt"
)

// State — конечное состояние сделки M2M.
type State string

const (
	StateDraft            State = "draft"
	StateValidated        State = "validated"
	StateSubmittedToNSD   State = "submitted_to_nsd"
	StateAwaitingDecision State = "awaiting_decision"
	StateConfirmed        State = "confirmed"
	StateAwaitingSUB16    State = "awaiting_sub16"
	StateDone             State = "done"
	StateRejected         State = "rejected"
	StateTimedOut         State = "timed_out"
	StateManualApproval   State = "manual_approval"
)

// ErrInvalidTransition возвращается при попытке перейти в состояние,
// которое не разрешено из текущего.
var ErrInvalidTransition = errors.New("m2mcore: недопустимый переход FSM")

// allowedTransitions — карта разрешённых переходов FSM сделки.
// Любая попытка перейти в state, отсутствующее в списке для текущего,
// заканчивается ErrInvalidTransition.
var allowedTransitions = map[State]map[State]struct{}{
	StateDraft: {
		StateValidated:      {},
		StateRejected:       {},
		StateManualApproval: {},
	},
	StateValidated: {
		StateSubmittedToNSD: {},
		StateRejected:       {},
		StateManualApproval: {},
	},
	StateSubmittedToNSD: {
		StateAwaitingDecision: {},
		StateRejected:         {},
	},
	StateAwaitingDecision: {
		StateConfirmed:      {},
		StateRejected:       {},
		StateTimedOut:       {},
		StateManualApproval: {},
	},
	StateConfirmed: {
		StateAwaitingSUB16: {},
		StateDone:          {},
	},
	StateAwaitingSUB16: {
		StateDone: {},
	},
	StateManualApproval: {
		StateValidated: {},
		StateConfirmed: {},
		StateRejected:  {},
	},
	// Завершающие состояния — без выходов.
	StateDone:     {},
	StateRejected: {},
	StateTimedOut: {},
}

// IsTerminal возвращает true для завершающих состояний.
func IsTerminal(s State) bool {
	switch s {
	case StateDone, StateRejected, StateTimedOut:
		return true
	}
	return false
}

// CanTransition сообщает, разрешён ли переход from -> to.
func CanTransition(from, to State) bool {
	allowed, ok := allowedTransitions[from]
	if !ok {
		return false
	}
	_, ok = allowed[to]
	return ok
}

// transition проверяет переход и возвращает обёрнутую ошибку с
// контекстом, если он недопустим.
func transition(from, to State) error {
	if !CanTransition(from, to) {
		return fmt.Errorf("%w: %s -> %s", ErrInvalidTransition, from, to)
	}
	return nil
}
