package judge

import (
	"fmt"
	"sync"
)

// Judge represents the interface for custom judge implementations
type Judge interface {
	// Name returns the judge name
	Name() string
	// Judge evaluates a task implementation
	Judge(taskID string, input map[string]interface{}) (map[string]interface{}, error)
	// Validate checks judge configuration
	Validate() error
}

// CustomJudgeRegistry manages custom judge implementations
type CustomJudgeRegistry struct {
	mu           sync.RWMutex
	judges       map[string]Judge
	defaultJudge Judge
}

// NewCustomJudgeRegistry creates a new custom judge registry
func NewCustomJudgeRegistry() *CustomJudgeRegistry {
	return &CustomJudgeRegistry{
		judges: make(map[string]Judge),
	}
}

// Register registers a custom judge
func (cjr *CustomJudgeRegistry) Register(name string, judge Judge) error {
	if name == "" || judge == nil {
		return fmt.Errorf("name and judge cannot be empty")
	}

	if err := judge.Validate(); err != nil {
		return fmt.Errorf("judge validation failed: %w", err)
	}

	cjr.mu.Lock()
	defer cjr.mu.Unlock()

	if _, exists := cjr.judges[name]; exists {
		return fmt.Errorf("judge already registered: %s", name)
	}

	cjr.judges[name] = judge
	return nil
}

// Unregister removes a judge
func (cjr *CustomJudgeRegistry) Unregister(name string) error {
	cjr.mu.Lock()
	defer cjr.mu.Unlock()

	if _, exists := cjr.judges[name]; !exists {
		return fmt.Errorf("judge not found: %s", name)
	}

	delete(cjr.judges, name)
	return nil
}

// Get retrieves a judge by name
func (cjr *CustomJudgeRegistry) Get(name string) (Judge, bool) {
	cjr.mu.RLock()
	defer cjr.mu.RUnlock()

	judge, exists := cjr.judges[name]
	return judge, exists
}

// Judge executes judgment with custom judge
func (cjr *CustomJudgeRegistry) Judge(name string, taskID string, input map[string]interface{}) (map[string]interface{}, error) {
	judge, exists := cjr.Get(name)
	if !exists {
		return nil, fmt.Errorf("judge not found: %s", name)
	}

	return judge.Judge(taskID, input)
}

// SetDefaultJudge sets the default judge
func (cjr *CustomJudgeRegistry) SetDefaultJudge(judge Judge) error {
	if err := judge.Validate(); err != nil {
		return fmt.Errorf("judge validation failed: %w", err)
	}

	cjr.mu.Lock()
	defer cjr.mu.Unlock()

	cjr.defaultJudge = judge
	return nil
}

// GetDefaultJudge gets the default judge
func (cjr *CustomJudgeRegistry) GetDefaultJudge() Judge {
	cjr.mu.RLock()
	defer cjr.mu.RUnlock()

	return cjr.defaultJudge
}

// ListJudges returns all registered judges
func (cjr *CustomJudgeRegistry) ListJudges() map[string]Judge {
	cjr.mu.RLock()
	defer cjr.mu.RUnlock()

	result := make(map[string]Judge)
	for name, judge := range cjr.judges {
		result[name] = judge
	}

	return result
}
