package platform

import (
	"fmt"
	"sort"
	"strings"
	"sync"

	"github.com/sirupsen/logrus"

	"github.com/titansys/appy-builder/internal/config"
	"github.com/titansys/appy-builder/internal/models"
)

// Registry manages platform builders and routes builds to the appropriate platform
type Registry struct {
	builders map[string]PlatformBuilder
	logger   *logrus.Logger
	mu       sync.RWMutex
}

// DefaultPlatform is the fallback platform when none is specified
const DefaultPlatform = "android-webview"

// NewRegistry creates a new platform registry by instantiating all registered factories.
// Platforms register themselves via init() in their register.go files.
func NewRegistry(cfg *config.Config, logger *logrus.Logger) *Registry {
	r := &Registry{
		builders: make(map[string]PlatformBuilder),
		logger:   logger,
	}

	// Instantiate all registered platform factories
	factories := getFactories()
	for _, factory := range factories {
		builder := factory(cfg, logger)
		r.Register(builder)
	}

	if len(r.builders) == 0 {
		logger.Warn("No platforms registered - ensure platform packages are imported")
	}

	return r
}

// Register adds a platform builder to the registry
func (r *Registry) Register(builder PlatformBuilder) {
	r.mu.Lock()
	defer r.mu.Unlock()
	r.builders[builder.PlatformID()] = builder
	r.logger.WithField("platform", builder.PlatformID()).Info("Registered platform builder")
}

// Get retrieves a platform builder by ID
func (r *Registry) Get(platformID string) (PlatformBuilder, error) {
	r.mu.RLock()
	defer r.mu.RUnlock()

	builder, ok := r.builders[platformID]
	if !ok {
		return nil, fmt.Errorf("unsupported platform: %s", platformID)
	}
	return builder, nil
}

// Build routes the build to the appropriate platform builder
func (r *Registry) Build(req models.BuildRequest) (string, error) {
	path, _, err := r.BuildWithLogs(req)
	return path, err
}

// BuildWithLogs routes the build to the appropriate platform builder with logs
func (r *Registry) BuildWithLogs(req models.BuildRequest) (string, string, error) {
	platform := req.Platform
	if platform == "" {
		platform = r.getDefaultPlatform()
	}

	r.logger.WithFields(logrus.Fields{
		"build_id": req.ID,
		"platform": platform,
	}).Info("Routing build to platform-specific builder")

	builder, err := r.Get(platform)
	if err != nil {
		return "", "", fmt.Errorf("unsupported platform: %s (supported: %s)", platform, r.supportedPlatformsString())
	}

	return builder.BuildWithLogs(req)
}

// getDefaultPlatform returns the default platform ID.
// Prefers "android-webview" if registered, otherwise returns first registered (sorted).
func (r *Registry) getDefaultPlatform() string {
	r.mu.RLock()
	defer r.mu.RUnlock()

	// Prefer android-webview if registered
	if _, ok := r.builders[DefaultPlatform]; ok {
		return DefaultPlatform
	}

	// Otherwise return first available (sorted for determinism)
	ids := make([]string, 0, len(r.builders))
	for id := range r.builders {
		ids = append(ids, id)
	}
	if len(ids) > 0 {
		sort.Strings(ids)
		return ids[0]
	}

	return DefaultPlatform // Will fail at Get() with proper error
}

// supportedPlatformsString returns comma-separated list of registered platforms
func (r *Registry) supportedPlatformsString() string {
	r.mu.RLock()
	defer r.mu.RUnlock()

	if len(r.builders) == 0 {
		return "none"
	}

	ids := make([]string, 0, len(r.builders))
	for id := range r.builders {
		ids = append(ids, id)
	}
	sort.Strings(ids)
	return strings.Join(ids, ", ")
}

// PlatformID returns the platform ID (for interface compliance - returns default)
func (r *Registry) PlatformID() string {
	return "registry"
}

// SetAppyClient sets the Appy client for all registered builders
func (r *Registry) SetAppyClient(client interface {
	DownloadKeystore(keystoreID string) ([]byte, error)
	DownloadKeystoreDynamic(keystoreID, siteURL, authKey string) ([]byte, error)
}) {
	r.mu.RLock()
	defer r.mu.RUnlock()

	for _, builder := range r.builders {
		builder.SetAppyClient(client)
	}
}

// NewBuilder creates a new registry (for backward compatibility)
func NewBuilder(cfg *config.Config, logger *logrus.Logger) *Registry {
	return NewRegistry(cfg, logger)
}
