package backend

import (
	"context"
	"sync"

	"github.com/gruntwork-io/terragrunt/internal/venv"
	"github.com/gruntwork-io/terragrunt/pkg/log"
	"github.com/puzpuzpuz/xsync/v4"
)

var _ Backend = new(CommonBackend)

type CommonBackend struct {
	bucketLocks   *xsync.Map[string, *sync.Mutex]
	initedConfigs *xsync.Map[string, bool]
	name          string
}

func NewCommonBackend(name string) *CommonBackend {
	return &CommonBackend{
		name:          name,
		bucketLocks:   xsync.NewMap[string, *sync.Mutex](),
		initedConfigs: xsync.NewMap[string, bool](),
	}
}

// Name implements `backends.Backend` interface.
func (backend *CommonBackend) Name() string {
	return backend.name
}

func (backend *CommonBackend) IsVersionControlEnabled(
	ctx context.Context,
	l log.Logger,
	v *venv.Venv,
	config Config,
	opts *Options,
) (bool, error) {
	l.Warnf("Checking version control for %s backend not implemented.", backend.Name())

	return false, nil
}

// NeedsBootstrap implements `backends.NeedsBootstrap` interface.
func (backend *CommonBackend) NeedsBootstrap(
	ctx context.Context,
	l log.Logger,
	v *venv.Venv,
	config Config,
	opts *Options,
) (bool, error) {
	return false, nil
}

// Bootstrap implements `backends.Bootstrap` interface.
func (backend *CommonBackend) Bootstrap(
	ctx context.Context,
	l log.Logger,
	v *venv.Venv,
	config Config,
	opts *Options,
) error {
	l.Warnf("Bootstrap for %s backend not implemented.", backend.Name())

	return nil
}

// Migrate implements `backends.Migrate` interface.
func (backend *CommonBackend) Migrate(
	ctx context.Context,
	l log.Logger,
	v *venv.Venv,
	srcConfig, dstConfig Config,
	opts *Options,
) error {
	l.Warnf("Migrate for %s backend not implemented.", backend.Name())

	return nil
}

// Delete implements `backends.Delete` interface.
func (backend *CommonBackend) Delete(
	ctx context.Context,
	l log.Logger,
	v *venv.Venv,
	config Config,
	opts *Options,
) error {
	l.Warnf("Delete for %s backend not implemented.", backend.Name())

	return nil
}

// DeleteBucket implements `backends.DeleteBucket` interface.
func (backend *CommonBackend) DeleteBucket(
	ctx context.Context,
	l log.Logger,
	v *venv.Venv,
	config Config,
	opts *Options,
) error {
	l.Warnf("Deleting entire bucket for %s backend not implemented.", backend.Name())

	return nil
}

// GetTFInitArgs implements `backends.GetTFInitArgs` interface.
func (backend *CommonBackend) GetTFInitArgs(config Config) map[string]any {
	return config
}

func (backend *CommonBackend) GetBucketMutex(bucketName string) *sync.Mutex {
	mu, _ := backend.bucketLocks.LoadOrCompute(bucketName, func() (*sync.Mutex, bool) {
		return new(sync.Mutex), false
	})

	return mu
}

func (backend *CommonBackend) IsConfigInited(config interface{ CacheKey() string }) bool {
	status, ok := backend.initedConfigs.Load(config.CacheKey())

	return ok && status
}

func (backend *CommonBackend) MarkConfigInited(config interface{ CacheKey() string }) {
	backend.initedConfigs.Store(config.CacheKey(), true)
}
