package repositories

import (
	"context"
	"time"

	"github.com/google/uuid"
)

// SessionEventType represents the type of session event
type SessionEventType string

const (
	// Session lifecycle events
	EventSessionCreated   SessionEventType = "session_created"
	EventPartyJoined      SessionEventType = "party_joined"
	EventPartyReady       SessionEventType = "party_ready"
	EventRoundStarted     SessionEventType = "round_started"
	EventRoundCompleted   SessionEventType = "round_completed"
	EventSessionCompleted SessionEventType = "session_completed"
	EventSessionFailed    SessionEventType = "session_failed"
	EventSessionExpired   SessionEventType = "session_expired"

	// Delegate events
	EventDelegateShareSent SessionEventType = "delegate_share_sent"

	// Signing config events
	EventSigningConfigSet     SessionEventType = "signing_config_set"
	EventSigningConfigCleared SessionEventType = "signing_config_cleared"
)

// SessionType represents the type of MPC session
type SessionType string

const (
	SessionTypeKeygen SessionType = "keygen"
	SessionTypeSign   SessionType = "sign"
)

// SessionEvent represents an immutable event in the session lifecycle
type SessionEvent struct {
	ID           uuid.UUID
	SessionID    uuid.UUID
	Username     string
	EventType    SessionEventType
	SessionType  SessionType
	ThresholdN   *int
	ThresholdT   *int
	PartyID      *string
	PartyIndex   *int
	MessageHash  []byte
	PublicKey    []byte
	Signature    []byte
	ErrorMessage *string
	Metadata     map[string]interface{}
	CreatedAt    time.Time
}

// NewSessionEvent creates a new session event with required fields
func NewSessionEvent(
	sessionID uuid.UUID,
	username string,
	eventType SessionEventType,
	sessionType SessionType,
) *SessionEvent {
	return &SessionEvent{
		ID:          uuid.New(),
		SessionID:   sessionID,
		Username:    username,
		EventType:   eventType,
		SessionType: sessionType,
		CreatedAt:   time.Now().UTC(),
	}
}

// WithThreshold adds threshold info to the event
func (e *SessionEvent) WithThreshold(n, t int) *SessionEvent {
	e.ThresholdN = &n
	e.ThresholdT = &t
	return e
}

// WithParty adds party info to the event
func (e *SessionEvent) WithParty(partyID string, partyIndex int) *SessionEvent {
	e.PartyID = &partyID
	e.PartyIndex = &partyIndex
	return e
}

// WithMessageHash adds message hash to the event
func (e *SessionEvent) WithMessageHash(hash []byte) *SessionEvent {
	e.MessageHash = hash
	return e
}

// WithPublicKey adds public key to the event
func (e *SessionEvent) WithPublicKey(key []byte) *SessionEvent {
	e.PublicKey = key
	return e
}

// WithSignature adds signature to the event
func (e *SessionEvent) WithSignature(sig []byte) *SessionEvent {
	e.Signature = sig
	return e
}

// WithError adds error message to the event
func (e *SessionEvent) WithError(msg string) *SessionEvent {
	e.ErrorMessage = &msg
	return e
}

// WithMetadata adds metadata to the event
func (e *SessionEvent) WithMetadata(metadata map[string]interface{}) *SessionEvent {
	e.Metadata = metadata
	return e
}

// SessionEventRepository defines the interface for session event persistence
// This is an append-only repository - events are never updated or deleted
type SessionEventRepository interface {
	// Create inserts a new event (append-only, never update)
	Create(ctx context.Context, event *SessionEvent) error

	// GetBySessionID retrieves all events for a session, ordered by creation time
	GetBySessionID(ctx context.Context, sessionID uuid.UUID) ([]*SessionEvent, error)

	// GetByUsername retrieves all events for a user, ordered by creation time desc
	GetByUsername(ctx context.Context, username string, limit int) ([]*SessionEvent, error)

	// GetLatestBySessionID retrieves the most recent event for a session
	GetLatestBySessionID(ctx context.Context, sessionID uuid.UUID) (*SessionEvent, error)

	// GetByUsernameAndType retrieves events for a user filtered by session type
	GetByUsernameAndType(ctx context.Context, username string, sessionType SessionType, limit int) ([]*SessionEvent, error)
}
