package mongo

import (
	"context"
	"fmt"
	"time"

	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
	"go.mongodb.org/mongo-driver/mongo/readpref"

	"bit.admedia.com/scm/ad/adpilot-indexing-commit-intel.com/internal/config"
)

const readyTimeout = 2 * time.Second

// Store reads graph deltas and persists commit analyses in MongoDB.
type Store struct {
	client               *mongo.Client
	database             *mongo.Database
	deltasDatabase       *mongo.Database
	indexingRunsDatabase *mongo.Database
	indexingRunsEnabled  bool
}

// New connects to MongoDB using configuration.
func New(cfg config.MongoConfig) (*Store, error) {
	if cfg.URI == "" {
		return nil, fmt.Errorf("mongodb uri is required")
	}
	if cfg.Database == "" {
		return nil, fmt.Errorf("mongodb database is required")
	}

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

	client, err := mongo.Connect(ctx, options.Client().ApplyURI(cfg.URI))
	if err != nil {
		return nil, fmt.Errorf("connect mongodb: %w", err)
	}

	deltasDB := cfg.DeltasDatabase
	if deltasDB == "" {
		deltasDB = "adpilot_code_parser"
	}
	indexingRunsDB := cfg.IndexingRunsDatabase
	if indexingRunsDB == "" {
		indexingRunsDB = "adpilot_repo_sync"
	}

	return &Store{
		client:               client,
		database:             client.Database(cfg.Database),
		deltasDatabase:       client.Database(deltasDB),
		indexingRunsDatabase: client.Database(indexingRunsDB),
		indexingRunsEnabled:  cfg.IndexingRunsEnabled,
	}, nil
}

// Ping checks MongoDB connectivity.
func (s *Store) Ping(ctx context.Context) error {
	if s == nil || s.client == nil {
		return fmt.Errorf("mongodb client is nil")
	}
	return s.client.Ping(ctx, readpref.Primary())
}

// Ready reports whether MongoDB responds to ping within a short timeout.
func (s *Store) Ready(ctx context.Context) bool {
	if s == nil || s.client == nil {
		return false
	}
	ctx, cancel := context.WithTimeout(ctx, readyTimeout)
	defer cancel()
	return s.Ping(ctx) == nil
}

// Close disconnects the MongoDB client.
func (s *Store) Close(ctx context.Context) error {
	if s == nil || s.client == nil {
		return nil
	}
	return s.client.Disconnect(ctx)
}

func (s *Store) collection(name string) *mongo.Collection {
	return s.database.Collection(name)
}

func (s *Store) deltasCollection(name string) *mongo.Collection {
	return s.deltasDatabase.Collection(name)
}

func (s *Store) indexingRunsCollection(name string) *mongo.Collection {
	return s.indexingRunsDatabase.Collection(name)
}
