// Package modules — Loader de modules.
// Découvre les modules disponibles, vérifie leur état en DB, et les initialise si activés.
// Un module désactivé ne fait appel à aucune de ses méthodes Register().
package modules

import (
	"database/sql"
	"fmt"
	"log"
	"net/http"
)

// Loader charge et gère les modules actifs.
type Loader struct {
	db       *sql.DB
	registry *coreRegistry
	modules  []Module
}

// NewLoader crée un Loader avec le router et la DB fournis.
func NewLoader(db *sql.DB) *Loader {
	return &Loader{
		db:       db,
		registry: newCoreRegistry(db),
	}
}

// RegisterModule enregistre un module disponible (appelé à l'init, depuis main.go).
// Le module sera initialisé seulement s'il est activé en base.
func (l *Loader) RegisterModule(m Module) {
	l.modules = append(l.modules, m)
}

// LoadActive charge et initialise tous les modules activés en base de données.
func (l *Loader) LoadActive() error {
	for _, m := range l.modules {
		enabled, err := l.isEnabled(m.ID())
		if err != nil {
			return fmt.Errorf("vérification module %s : %w", m.ID(), err)
		}
		if !enabled {
			log.Printf("Module %s : désactivé, ignoré", m.ID())
			continue
		}

		log.Printf("Module %s : chargement...", m.ID())
		if err := m.Register(l.registry); err != nil {
			return fmt.Errorf("initialisation module %s : %w", m.ID(), err)
		}
		log.Printf("Module %s : chargé avec succès", m.ID())
	}
	return nil
}

// isEnabled vérifie en base de données si un module est activé.
func (l *Loader) isEnabled(id string) (bool, error) {
	var enabled int
	err := l.db.QueryRow(`SELECT is_enabled FROM modules WHERE id = ?`, id).Scan(&enabled)
	if err == sql.ErrNoRows {
		return false, nil // Module inconnu = désactivé
	}
	return enabled == 1, err
}

// Registry retourne le registry partagé (pour accès par le serveur HTTP).
func (l *Loader) Registry() *coreRegistry {
	return l.registry
}

// ---- Implémentation interne du Registry ----

// RouteEntry décrit une route HTTP enregistrée par un module.
type RouteEntry struct {
	Method       string
	Path         string
	Handler      http.HandlerFunc
	RequireAdmin bool
}

type migrationEntry struct {
	version int
	sql     string
	fn      MigrationFn
}

type translationEntry struct {
	lang string
	keys map[string]string
}

// coreRegistry implémente l'interface Registry.
type coreRegistry struct {
	db           *sql.DB
	routes       []RouteEntry
	wsChannels   map[string]WSHandler
	widgets      []WidgetDef
	settingsTabs []SettingsTabDef
	migrations   []migrationEntry
	translations []translationEntry
}

func newCoreRegistry(db *sql.DB) *coreRegistry {
	return &coreRegistry{
		db:         db,
		wsChannels: make(map[string]WSHandler),
	}
}

func (r *coreRegistry) RegisterRoute(method, path string, handler http.HandlerFunc, requireAdmin bool) {
	r.routes = append(r.routes, RouteEntry{method, path, handler, requireAdmin})
}

func (r *coreRegistry) RegisterWSChannel(channel string, handler WSHandler) {
	r.wsChannels[channel] = handler
}

func (r *coreRegistry) RegisterWidget(widget WidgetDef) {
	r.widgets = append(r.widgets, widget)
}

func (r *coreRegistry) RegisterSettingsTab(tab SettingsTabDef) {
	r.settingsTabs = append(r.settingsTabs, tab)
}

func (r *coreRegistry) RegisterTranslations(lang string, keys map[string]string) {
	r.translations = append(r.translations, translationEntry{lang, keys})
}

func (r *coreRegistry) RegisterMigration(version int, sqlStr string, fn MigrationFn) {
	r.migrations = append(r.migrations, migrationEntry{version, sqlStr, fn})
}

func (r *coreRegistry) DB() *sql.DB {
	return r.db
}

// GetRoutes retourne les routes enregistrées par les modules.
func (r *coreRegistry) GetRoutes() []RouteEntry {
	return r.routes
}

// GetWidgets retourne les types de widgets disponibles.
func (r *coreRegistry) GetWidgets() []WidgetDef {
	return r.widgets
}

// GetSettingsTabs retourne les onglets de paramètres des modules.
func (r *coreRegistry) GetSettingsTabs() []SettingsTabDef {
	return r.settingsTabs
}
