package entities

import (
	"time"

	"github.com/google/uuid"
	"github.com/rwadurian/mpc-system/services/account/domain/value_objects"
)

// RecoverySession represents an account recovery session
type RecoverySession struct {
	ID                 uuid.UUID
	AccountID          value_objects.AccountID
	RecoveryType       value_objects.RecoveryType
	OldShareType       *value_objects.ShareType
	NewKeygenSessionID *uuid.UUID
	Status             value_objects.RecoveryStatus
	RequestedAt        time.Time
	CompletedAt        *time.Time
}

// NewRecoverySession creates a new RecoverySession
func NewRecoverySession(
	accountID value_objects.AccountID,
	recoveryType value_objects.RecoveryType,
) *RecoverySession {
	return &RecoverySession{
		ID:           uuid.New(),
		AccountID:    accountID,
		RecoveryType: recoveryType,
		Status:       value_objects.RecoveryStatusRequested,
		RequestedAt:  time.Now().UTC(),
	}
}

// SetOldShareType sets the old share type being replaced
func (r *RecoverySession) SetOldShareType(shareType value_objects.ShareType) {
	r.OldShareType = &shareType
}

// StartKeygen starts the keygen process for recovery
func (r *RecoverySession) StartKeygen(keygenSessionID uuid.UUID) error {
	if r.Status != value_objects.RecoveryStatusRequested {
		return ErrRecoveryInvalidState
	}
	r.NewKeygenSessionID = &keygenSessionID
	r.Status = value_objects.RecoveryStatusInProgress
	return nil
}

// Complete marks the recovery as completed
func (r *RecoverySession) Complete() error {
	if r.Status != value_objects.RecoveryStatusInProgress {
		return ErrRecoveryInvalidState
	}
	now := time.Now().UTC()
	r.CompletedAt = &now
	r.Status = value_objects.RecoveryStatusCompleted
	return nil
}

// Fail marks the recovery as failed
func (r *RecoverySession) Fail() error {
	if r.Status == value_objects.RecoveryStatusCompleted {
		return ErrRecoveryAlreadyCompleted
	}
	r.Status = value_objects.RecoveryStatusFailed
	return nil
}

// IsCompleted checks if recovery is completed
func (r *RecoverySession) IsCompleted() bool {
	return r.Status == value_objects.RecoveryStatusCompleted
}

// IsFailed checks if recovery failed
func (r *RecoverySession) IsFailed() bool {
	return r.Status == value_objects.RecoveryStatusFailed
}

// IsInProgress checks if recovery is in progress
func (r *RecoverySession) IsInProgress() bool {
	return r.Status == value_objects.RecoveryStatusInProgress
}

// Validate validates the recovery session
func (r *RecoverySession) Validate() error {
	if r.AccountID.IsZero() {
		return ErrRecoveryInvalidAccountID
	}
	if !r.RecoveryType.IsValid() {
		return ErrRecoveryInvalidType
	}
	return nil
}

// Recovery errors
var (
	ErrRecoveryInvalidAccountID = &AccountError{Code: "RECOVERY_INVALID_ACCOUNT_ID", Message: "invalid account ID for recovery"}
	ErrRecoveryInvalidType      = &AccountError{Code: "RECOVERY_INVALID_TYPE", Message: "invalid recovery type"}
	ErrRecoveryInvalidState     = &AccountError{Code: "RECOVERY_INVALID_STATE", Message: "invalid recovery state for this operation"}
	ErrRecoveryAlreadyCompleted = &AccountError{Code: "RECOVERY_ALREADY_COMPLETED", Message: "recovery already completed"}
	ErrRecoveryNotFound         = &AccountError{Code: "RECOVERY_NOT_FOUND", Message: "recovery session not found"}
)
