package mongo

import (
	"context"
	"errors"
	"time"

	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/primitive"
	mongodriver "go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"

	"scheduler-backend/internal/store/model"
)

const schedulerGlobalConfigKey = "scheduler"
const defaultSchedulerGlobalConfigJSON = `{
  "maxConcurrentJobs": 5,
  "defaultTimeoutSeconds": 300
}`

type GlobalConfigStore struct {
	collection *mongodriver.Collection
}

func NewGlobalConfigStore(db *mongodriver.Database) *GlobalConfigStore {
	return &GlobalConfigStore{
		collection: db.Collection("global_config"),
	}
}

func (s *GlobalConfigStore) Get(ctx context.Context, key string) (*model.GlobalConfig, error) {
	findCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
	defer cancel()

	var item model.GlobalConfig
	err := s.collection.FindOne(findCtx, bson.M{"key": key}).Decode(&item)
	if err == nil {
		return &item, nil
	}
	if !errors.Is(err, mongodriver.ErrNoDocuments) {
		return nil, err
	}

	item = model.GlobalConfig{
		ID:        primitive.NewObjectID(),
		Key:       key,
		Config:    defaultConfigForKey(key),
		UpdatedBy: "system",
		UpdatedAt: time.Now(),
	}
	if _, err := s.collection.InsertOne(findCtx, item); err != nil {
		return nil, err
	}
	return &item, nil
}

func (s *GlobalConfigStore) Upsert(ctx context.Context, item *model.GlobalConfig) error {
	updateCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
	defer cancel()

	item.UpdatedAt = time.Now()
	if item.UpdatedBy == "" {
		item.UpdatedBy = "system"
	}
	if item.Key == "" {
		item.Key = schedulerGlobalConfigKey
	}

	_, err := s.collection.UpdateOne(updateCtx, bson.M{"key": item.Key}, bson.M{
		"$set": bson.M{
			"key":       item.Key,
			"config":    item.Config,
			"updatedBy": item.UpdatedBy,
			"updatedAt": item.UpdatedAt,
		},
	}, options.Update().SetUpsert(true))
	return err
}

func defaultConfigForKey(key string) string {
	if key == schedulerGlobalConfigKey {
		return defaultSchedulerGlobalConfigJSON
	}
	return "{}"
}
