package repositories

import (
	"context"
	"time"

	"github.com/google/uuid"
	"github.com/rwadurian/mpc-system/services/session-coordinator/domain/entities"
	"github.com/rwadurian/mpc-system/services/session-coordinator/domain/value_objects"
)

// MessageRepository defines the interface for message persistence
// This is a port in Hexagonal Architecture
type MessageRepository interface {
	// SaveMessage persists a new message
	SaveMessage(ctx context.Context, msg *entities.SessionMessage) error

	// GetByID retrieves a message by ID
	GetByID(ctx context.Context, id uuid.UUID) (*entities.SessionMessage, error)

	// GetMessages retrieves messages for a session and party after a specific time
	GetMessages(
		ctx context.Context,
		sessionID value_objects.SessionID,
		partyID value_objects.PartyID,
		afterTime time.Time,
	) ([]*entities.SessionMessage, error)

	// GetUndeliveredMessages retrieves undelivered messages for a party
	GetUndeliveredMessages(
		ctx context.Context,
		sessionID value_objects.SessionID,
		partyID value_objects.PartyID,
	) ([]*entities.SessionMessage, error)

	// GetMessagesByRound retrieves messages for a specific round
	GetMessagesByRound(
		ctx context.Context,
		sessionID value_objects.SessionID,
		roundNumber int,
	) ([]*entities.SessionMessage, error)

	// MarkDelivered marks a message as delivered
	MarkDelivered(ctx context.Context, messageID uuid.UUID) error

	// MarkAllDelivered marks all messages for a party as delivered
	MarkAllDelivered(
		ctx context.Context,
		sessionID value_objects.SessionID,
		partyID value_objects.PartyID,
	) error

	// DeleteBySession deletes all messages for a session
	DeleteBySession(ctx context.Context, sessionID value_objects.SessionID) error

	// DeleteOlderThan deletes messages older than a specific time
	DeleteOlderThan(ctx context.Context, before time.Time) (int64, error)

	// Count returns the total number of messages for a session
	Count(ctx context.Context, sessionID value_objects.SessionID) (int64, error)

	// CountUndelivered returns the number of undelivered messages for a party
	CountUndelivered(
		ctx context.Context,
		sessionID value_objects.SessionID,
		partyID value_objects.PartyID,
	) (int64, error)
}

// MessageQueryOptions defines options for querying messages
type MessageQueryOptions struct {
	SessionID   value_objects.SessionID
	PartyID     *value_objects.PartyID
	RoundNumber *int
	AfterTime   *time.Time
	OnlyUndelivered bool
	Limit       int
	Offset      int
}

// NewMessageQueryOptions creates default query options
func NewMessageQueryOptions(sessionID value_objects.SessionID) *MessageQueryOptions {
	return &MessageQueryOptions{
		SessionID: sessionID,
		Limit:     100,
		Offset:    0,
	}
}

// ForParty filters messages for a specific party
func (o *MessageQueryOptions) ForParty(partyID value_objects.PartyID) *MessageQueryOptions {
	o.PartyID = &partyID
	return o
}

// ForRound filters messages for a specific round
func (o *MessageQueryOptions) ForRound(roundNumber int) *MessageQueryOptions {
	o.RoundNumber = &roundNumber
	return o
}

// After filters messages after a specific time
func (o *MessageQueryOptions) After(t time.Time) *MessageQueryOptions {
	o.AfterTime = &t
	return o
}

// Undelivered filters only undelivered messages
func (o *MessageQueryOptions) Undelivered() *MessageQueryOptions {
	o.OnlyUndelivered = true
	return o
}

// WithPagination sets pagination options
func (o *MessageQueryOptions) WithPagination(limit, offset int) *MessageQueryOptions {
	o.Limit = limit
	o.Offset = offset
	return o
}
