package mongo

import (
	"context"
	"time"

	"github.com/tech/sendico/billing/documents/storage"
	"github.com/tech/sendico/billing/documents/storage/mongo/store"
	"github.com/tech/sendico/pkg/db"
	"github.com/tech/sendico/pkg/merrors"
	"github.com/tech/sendico/pkg/mlogger"
	"go.mongodb.org/mongo-driver/v2/mongo"
	"go.uber.org/zap"
)

type Store struct {
	logger    mlogger.Logger
	conn      *db.MongoConnection
	db        *mongo.Database
	documents storage.DocumentsStore
}

// New creates a repository backed by MongoDB for the billing documents service.
func New(logger mlogger.Logger, conn *db.MongoConnection) (*Store, error) {
	if conn == nil {
		return nil, merrors.InvalidArgument("mongo connection is nil")
	}

	client := conn.Client()
	if client == nil {
		return nil, merrors.Internal("mongo client not initialised")
	}

	database := conn.Database()
	result := &Store{
		logger: logger.Named("storage").Named("mongo"),
		conn:   conn,
		db:     database,
	}

	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	if err := result.Ping(ctx); err != nil {
		result.logger.Error("Mongo ping failed during store init", zap.Error(err))

		return nil, err
	}

	documentsStore, err := store.NewDocuments(result.logger, database)
	if err != nil {
		result.logger.Error("Failed to initialise documents store", zap.Error(err))

		return nil, err
	}

	result.documents = documentsStore

	result.logger.Info("Billing documents MongoDB storage initialised")

	return result, nil
}

func (s *Store) Ping(ctx context.Context) error {
	return s.conn.Ping(ctx)
}

func (s *Store) Documents() storage.DocumentsStore {
	return s.documents
}

var _ storage.Repository = (*Store)(nil)
