// Package core provides core interfaces and types for connectivity checkers.
package core

import (
	"context"
	"errors"
	"fmt"
	"sync"
)

// Checker defines the interface for all connectivity checks.
type Checker interface {
	// Check performs the connectivity check.
	Check(ctx context.Context) error
	// Type returns the checker type identifier.
	Type() string
}

// Factory creates a checker from type-specific parameters.
type Factory func(req *CheckRequest) (Checker, error)

// Registry manages checker factories.
type Registry struct {
	factories map[string]Factory
	mu        sync.RWMutex
}

// DefaultRegistry is the global checker registry.
var DefaultRegistry = NewRegistry()

// NewRegistry creates a new checker registry.
func NewRegistry() *Registry {
	return &Registry{
		factories: make(map[string]Factory),
	}
}

// Register adds a checker factory to the registry.
func (r *Registry) Register(connType string, factory Factory) {
	r.mu.Lock()
	defer r.mu.Unlock()
	r.factories[connType] = factory
}

// Create creates a checker using the registered factory.
func (r *Registry) Create(req *CheckRequest) (Checker, error) {
	if req == nil {
		return nil, errors.New("check request is nil")
	}
	if req.TargetType == "" {
		return nil, errors.New("type is required")
	}

	r.mu.RLock()
	factory, ok := r.factories[req.TargetType]
	r.mu.RUnlock()

	if !ok {
		return nil, fmt.Errorf("unknown checker type: %s", req.TargetType)
	}

	return factory(req)
}

// ListTypes returns all registered checker types.
func (r *Registry) ListTypes() []string {
	r.mu.RLock()
	defer r.mu.RUnlock()

	types := make([]string, 0, len(r.factories))
	for t := range r.factories {
		types = append(types, t)
	}
	return types
}

// MockChecker is a test checker implementation.
type MockChecker struct {
	CheckFunc func(ctx context.Context) error
	TypeName  string
}

func (m *MockChecker) Check(ctx context.Context) error {
	if m.CheckFunc != nil {
		return m.CheckFunc(ctx)
	}
	return nil
}

func (m *MockChecker) Type() string {
	return m.TypeName
}
