package errors

import (
	"errors"
	"fmt"
)

// Domain errors
var (
	// Session errors
	ErrSessionNotFound      = errors.New("session not found")
	ErrSessionExpired       = errors.New("session expired")
	ErrSessionAlreadyExists = errors.New("session already exists")
	ErrSessionFull          = errors.New("session is full")
	ErrSessionNotInProgress = errors.New("session not in progress")
	ErrInvalidSessionType   = errors.New("invalid session type")
	ErrInvalidThreshold     = errors.New("invalid threshold: t cannot exceed n")

	// Participant errors
	ErrParticipantNotFound    = errors.New("participant not found")
	ErrParticipantNotInvited  = errors.New("participant not invited")
	ErrInvalidJoinToken       = errors.New("invalid join token")
	ErrTokenMismatch          = errors.New("token mismatch")
	ErrParticipantAlreadyJoined = errors.New("participant already joined")

	// Message errors
	ErrMessageNotFound    = errors.New("message not found")
	ErrInvalidMessage     = errors.New("invalid message")
	ErrMessageDeliveryFailed = errors.New("message delivery failed")

	// Key share errors
	ErrKeyShareNotFound = errors.New("key share not found")
	ErrKeyShareCorrupted = errors.New("key share corrupted")
	ErrDecryptionFailed  = errors.New("decryption failed")

	// Account errors
	ErrAccountNotFound    = errors.New("account not found")
	ErrAccountExists      = errors.New("account already exists")
	ErrAccountSuspended   = errors.New("account suspended")
	ErrInvalidCredentials = errors.New("invalid credentials")

	// Crypto errors
	ErrInvalidPublicKey  = errors.New("invalid public key")
	ErrInvalidSignature  = errors.New("invalid signature")
	ErrSigningFailed     = errors.New("signing failed")
	ErrKeygenFailed      = errors.New("keygen failed")

	// Infrastructure errors
	ErrDatabaseConnection = errors.New("database connection error")
	ErrCacheConnection    = errors.New("cache connection error")
	ErrQueueConnection    = errors.New("queue connection error")
)

// DomainError represents a domain-specific error with additional context
type DomainError struct {
	Err     error
	Message string
	Code    string
	Details map[string]interface{}
}

func (e *DomainError) Error() string {
	if e.Message != "" {
		return fmt.Sprintf("%s: %v", e.Message, e.Err)
	}
	return e.Err.Error()
}

func (e *DomainError) Unwrap() error {
	return e.Err
}

// NewDomainError creates a new domain error
func NewDomainError(err error, code string, message string) *DomainError {
	return &DomainError{
		Err:     err,
		Code:    code,
		Message: message,
		Details: make(map[string]interface{}),
	}
}

// WithDetail adds additional context to the error
func (e *DomainError) WithDetail(key string, value interface{}) *DomainError {
	e.Details[key] = value
	return e
}

// ValidationError represents input validation errors
type ValidationError struct {
	Field   string
	Message string
}

func (e *ValidationError) Error() string {
	return fmt.Sprintf("validation error on field '%s': %s", e.Field, e.Message)
}

// NewValidationError creates a new validation error
func NewValidationError(field, message string) *ValidationError {
	return &ValidationError{
		Field:   field,
		Message: message,
	}
}

// NotFoundError represents a resource not found error
type NotFoundError struct {
	Resource string
	ID       string
}

func (e *NotFoundError) Error() string {
	return fmt.Sprintf("%s with id '%s' not found", e.Resource, e.ID)
}

// NewNotFoundError creates a new not found error
func NewNotFoundError(resource, id string) *NotFoundError {
	return &NotFoundError{
		Resource: resource,
		ID:       id,
	}
}

// Is checks if the target error matches
func Is(err, target error) bool {
	return errors.Is(err, target)
}

// As attempts to convert err to target type
func As(err error, target interface{}) bool {
	return errors.As(err, target)
}

// Wrap wraps an error with additional context
func Wrap(err error, message string) error {
	if err == nil {
		return nil
	}
	return fmt.Errorf("%s: %w", message, err)
}
