package storage

import (
	"context"
	"time"

	"github.com/tech/sendico/edge/callbacks/internal/model"
	"github.com/tech/sendico/pkg/db"
	"github.com/tech/sendico/pkg/mlogger"
	"go.mongodb.org/mongo-driver/v2/bson"
)

// TaskDefaults are applied when creating tasks.
type TaskDefaults struct {
	MaxAttempts    int
	MinDelay       time.Duration
	MaxDelay       time.Duration
	RequestTimeout time.Duration
}

// Options configures mongo collections.
type Options struct {
	InboxCollection     string
	TasksCollection     string
	EndpointsCollection string
}

// InboxRepo controls event dedupe state.
type InboxRepo interface {
	TryInsert(ctx context.Context, eventID, ceventType string, organizationRef bson.ObjectID, at time.Time) (bool, error)
}

// EndpointRepo resolves endpoints for events.
type EndpointRepo interface {
	FindActive(ctx context.Context, eventType string, organizationRef bson.ObjectID) ([]model.Endpoint, error)
}

// TaskRepo manages callback tasks.
type TaskRepo interface {
	UpsertTasks(ctx context.Context, eventID string, endpoints []model.Endpoint, payload []byte, defaults TaskDefaults, at time.Time) error
	LockNextTask(ctx context.Context, now time.Time, workerID string, lockTTL time.Duration) (*model.Task, error)
	MarkDelivered(ctx context.Context, taskID bson.ObjectID, httpCode int, latency time.Duration, at time.Time) error
	MarkRetry(ctx context.Context, taskID bson.ObjectID, attempt int, nextAttemptAt time.Time, lastError string, httpCode int, at time.Time) error
	MarkFailed(ctx context.Context, taskID bson.ObjectID, attempt int, lastError string, httpCode int, at time.Time) error
}

// Repository is the callbacks persistence contract.
type Repository interface {
	Inbox() InboxRepo
	Endpoints() EndpointRepo
	Tasks() TaskRepo
}

// New creates a Mongo-backed callbacks repository.
func New(logger mlogger.Logger, conn *db.MongoConnection) (Repository, error) {
	return newMongoRepository(logger, conn)
}
