package pages

import (
	"context"
	"log"
	"net/http"

	"github.com/gin-gonic/gin"

	"switchboard-core/middleware"
)

// SeedSurfaces writes core surface manifests to the registry table.
// Called once at startup. Does NOT overwrite the enabled flag — admin
// toggles survive restarts.
func (e *Engine) SeedSurfaces() {
	if e.stores.Packages == nil {
		log.Printf("[pages] Surface registry not available — skipping seed")
		return
	}
	ctx := context.Background()
	for _, s := range e.surfaces {
		manifest := map[string]any{
			"route":       s.Route,
			"alt_routes":  s.AltRoutes,
			"template":    s.Template,
			"components":  s.Components,
			"data_requires": s.DataRequires,
			"auth":        s.Auth,
			"layout":      s.Layout,
		}
		if err := e.stores.Packages.Seed(ctx, s.ID, s.Title, s.Source, manifest); err != nil {
			log.Printf("[pages] Failed to seed surface %q: %v", s.ID, err)
		}
	}
	log.Printf("[pages] Seeded %d core surfaces into registry", len(e.surfaces))

	// v0.31.0: Clean up old "editor" core surface row.
	// Editor is now an installable package — the old seed row would show a
	// broken nav link until the package .pkg is uploaded via admin UI.
	if sr, err := e.stores.Packages.Get(ctx, "editor"); err == nil && sr != nil && sr.Source == "extension" {
		if sr.Type == "" || sr.Type == "surface" {
			if delErr := e.stores.Packages.Delete(ctx, "editor"); delErr != nil {
				log.Printf("[pages] Failed to clean up old editor surface: %v", delErr)
			} else {
				log.Printf("[pages] Cleaned up old editor core surface — install editor .pkg via admin UI")
			}
		}
	}
}

// IsSurfaceEnabled checks if a surface is enabled in the registry.
// Admin is always enabled (system-critical).
// Returns true if the surface is not found (fail-open for backward compat).
func (e *Engine) IsSurfaceEnabled(surfaceID string) bool {
	if surfaceID == "admin" {
		return true
	}
	if e.stores.Packages == nil {
		return true // No registry = all surfaces enabled (backward compat)
	}
	ctx := context.Background()
	sr, err := e.stores.Packages.Get(ctx, surfaceID)
	if err != nil || sr == nil {
		return true // Not in registry = assume enabled (backward compat)
	}
	return sr.Enabled
}

// EnabledSurfaceIDs returns a list of enabled surface IDs for nav rendering.
func (e *Engine) EnabledSurfaceIDs() []string {
	if e.stores.Packages == nil {
		// No registry — return all core surface IDs
		var all []string
		for _, s := range e.surfaces {
			all = append(all, s.ID)
		}
		return all
	}
	ctx := context.Background()
	ids, err := e.stores.Packages.ListEnabled(ctx)
	if err != nil {
		log.Printf("[pages] Failed to load enabled surfaces: %v", err)
		// Fallback: return all core surface IDs
		var all []string
		for _, s := range e.surfaces {
			all = append(all, s.ID)
		}
		return all
	}
	return ids
}

// DefaultSurfaceRedirect returns a handler for GET / that redirects to the
// configured default surface, falling back to the first enabled extension
// surface, then /welcome.
//
// This route has no auth middleware, so we opportunistically read the JWT
// from the cookie to check user preferences. If the cookie is missing or
// invalid, user preference is skipped (falls through to global default).
func (e *Engine) DefaultSurfaceRedirect() gin.HandlerFunc {
	return func(c *gin.Context) {
		userID := middleware.UserIDFromCookie(c, e.cfg.JWTSecret)
		target := e.resolveDefaultSurface(c.Request.Context(), userID)
		c.Redirect(http.StatusTemporaryRedirect, e.cfg.BasePath+target)
	}
}

// resolveDefaultSurface returns the path to redirect to (without BasePath).
// Priority: user preference → global default_surface → first enabled extension → /welcome.
func (e *Engine) resolveDefaultSurface(ctx context.Context, userID string) string {
	if e.stores.GlobalConfig == nil || e.stores.Packages == nil {
		return "/welcome"
	}

	// 1. Check user preference (default_surface in user settings)
	if userID != "" && e.stores.Users != nil {
		if user, err := e.stores.Users.GetByID(ctx, userID); err == nil && user != nil {
			if id, _ := user.Settings["default_surface"].(string); id != "" {
				if path := e.surfacePath(ctx, id); path != "" {
					return path
				}
				// User's chosen surface is missing or disabled — fall through
			}
		}
	}

	// 2. Check admin-configured global default_surface
	if raw, err := e.stores.GlobalConfig.Get(ctx, "default_surface"); err == nil && raw != nil {
		if id, ok := raw["id"].(string); ok && id != "" {
			if path := e.surfacePath(ctx, id); path != "" {
				return path
			}
			// Configured surface is missing or disabled — fall through
		}
	}

	// 3. First enabled extension surface (type "surface" or "full")
	allPkgs, err := e.stores.Packages.List(ctx)
	if err == nil {
		for _, s := range allPkgs {
			if s.Source == "core" || s.Source == "builtin" {
				continue
			}
			if !s.Enabled {
				continue
			}
			if s.Type == "surface" || s.Type == "full" {
				return "/s/" + s.ID
			}
		}
	}

	// 4. Fallback — welcome surface (no extensions installed)
	return "/welcome"
}

// surfacePath returns the URL path for a surface ID, or "" if the surface
// doesn't exist or is disabled.
func (e *Engine) surfacePath(ctx context.Context, id string) string {
	pkg, err := e.stores.Packages.Get(ctx, id)
	if err != nil || pkg == nil || !pkg.Enabled {
		return ""
	}

	// Core surfaces live at /{id}, extension surfaces at /s/{slug}
	if pkg.Source == "core" {
		// Look up the core surface's base route
		if sm := e.GetSurface(id); sm != nil {
			// Use the first alt route (without params) or strip params from Route
			if len(sm.AltRoutes) > 0 {
				return sm.AltRoutes[0]
			}
		}
		return "/" + id
	}
	return "/s/" + id
}

// disabledRedirect returns a handler that redirects to /.
// The DefaultSurfaceRedirect handler will resolve to the appropriate surface.
func (e *Engine) disabledRedirect() gin.HandlerFunc {
	return func(c *gin.Context) {
		c.Redirect(http.StatusTemporaryRedirect, e.cfg.BasePath+"/admin")
	}
}
