package flags

import (
	"context"
	"fmt"
	"sync"
	"time"
)

// FeatureFlag represents a boolean on/off flag scoped to a tenant or global (tenant_id = "").
type FeatureFlag struct {
	ID        string
	TenantID  string // empty string = global flag
	Name      string
	IsEnabled bool
	CreatedAt time.Time
	UpdatedAt time.Time
}

// FlagStore is the persistence interface for feature flags.
type FlagStore interface {
	// IsEnabled returns true if the flag is enabled for the given tenant.
	// Lookup order: tenant-specific flag → global flag (tenant_id="") → false.
	IsEnabled(ctx context.Context, tenantID, name string) (bool, error)

	// Get returns a single flag by tenantID + name.
	Get(ctx context.Context, tenantID, name string) (FeatureFlag, error)

	// Set creates or updates a flag for the given tenant (or global if tenantID="").
	Set(ctx context.Context, tenantID, name string, enabled bool) (FeatureFlag, error)

	// List returns all flags for a tenant plus global flags.
	List(ctx context.Context, tenantID string) ([]FeatureFlag, error)

	// Delete removes a flag. Returns ErrNotFound if absent.
	Delete(ctx context.Context, tenantID, name string) error
}

// ErrNotFound is returned when a flag does not exist.
var ErrNotFound = fmt.Errorf("feature flag not found")

// ─── MemFlagStore ─────────────────────────────────────────────────────────────

// MemFlagStore is a thread-safe, in-memory FlagStore for tests and local dev.
type MemFlagStore struct {
	mu    sync.RWMutex
	flags map[string]FeatureFlag // key = tenantID + ":" + name (empty tenant = ":" + name)
	seq   int
}

func NewMemFlagStore() *MemFlagStore {
	return &MemFlagStore{flags: make(map[string]FeatureFlag)}
}

func flagKey(tenantID, name string) string { return tenantID + ":" + name }

func (m *MemFlagStore) IsEnabled(ctx context.Context, tenantID, name string) (bool, error) {
	m.mu.RLock()
	defer m.mu.RUnlock()

	// Tenant-specific flag takes precedence
	if f, ok := m.flags[flagKey(tenantID, name)]; ok {
		return f.IsEnabled, nil
	}
	// Global fallback
	if f, ok := m.flags[flagKey("", name)]; ok {
		return f.IsEnabled, nil
	}
	return false, nil
}

func (m *MemFlagStore) Get(ctx context.Context, tenantID, name string) (FeatureFlag, error) {
	m.mu.RLock()
	defer m.mu.RUnlock()

	f, ok := m.flags[flagKey(tenantID, name)]
	if !ok {
		return FeatureFlag{}, ErrNotFound
	}
	return f, nil
}

func (m *MemFlagStore) Set(ctx context.Context, tenantID, name string, enabled bool) (FeatureFlag, error) {
	m.mu.Lock()
	defer m.mu.Unlock()

	now := time.Now()
	key := flagKey(tenantID, name)

	existing, ok := m.flags[key]
	if ok {
		existing.IsEnabled = enabled
		existing.UpdatedAt = now
		m.flags[key] = existing
		return existing, nil
	}

	m.seq++
	f := FeatureFlag{
		ID:        fmt.Sprintf("mem-%d", m.seq),
		TenantID:  tenantID,
		Name:      name,
		IsEnabled: enabled,
		CreatedAt: now,
		UpdatedAt: now,
	}
	m.flags[key] = f
	return f, nil
}

func (m *MemFlagStore) List(ctx context.Context, tenantID string) ([]FeatureFlag, error) {
	m.mu.RLock()
	defer m.mu.RUnlock()

	var out []FeatureFlag
	for _, f := range m.flags {
		if f.TenantID == tenantID || f.TenantID == "" {
			out = append(out, f)
		}
	}
	return out, nil
}

func (m *MemFlagStore) Delete(ctx context.Context, tenantID, name string) error {
	m.mu.Lock()
	defer m.mu.Unlock()

	key := flagKey(tenantID, name)
	if _, ok := m.flags[key]; !ok {
		return ErrNotFound
	}
	delete(m.flags, key)
	return nil
}
