package handlers

import (
	"net/http"

	"github.com/gin-gonic/gin"

	"chat-switchboard/models"
	"chat-switchboard/providers"
	"chat-switchboard/roles"
	"chat-switchboard/store"
)

// RolesHandler manages model role configuration.
type RolesHandler struct {
	stores   store.Stores
	resolver *roles.Resolver
}

// NewRolesHandler creates a roles handler.
func NewRolesHandler(s store.Stores, resolver *roles.Resolver) *RolesHandler {
	return &RolesHandler{stores: s, resolver: resolver}
}

// ── List All Role Configs ──────────────────
// GET /admin/roles

func (h *RolesHandler) ListRoles(c *gin.Context) {
	allRoles, err := h.stores.GlobalConfig.Get(c.Request.Context(), "model_roles")
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to load roles"})
		return
	}
	c.JSON(http.StatusOK, allRoles)
}

// ── Get Single Role Config ─────────────────
// GET /admin/roles/:role

func (h *RolesHandler) GetRole(c *gin.Context) {
	role := c.Param("role")
	if !roles.IsValidRole(role) {
		c.JSON(http.StatusBadRequest, gin.H{"error": "unknown role: " + role})
		return
	}

	cfg, err := h.resolver.GetConfig(c.Request.Context(), role, "", nil)
	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, cfg)
}

// ── Update Role Config ─────────────────────
// PUT /admin/roles/:role

func (h *RolesHandler) UpdateRole(c *gin.Context) {
	role := c.Param("role")
	if !roles.IsValidRole(role) {
		c.JSON(http.StatusBadRequest, gin.H{"error": "unknown role: " + role})
		return
	}

	var req roles.RoleConfig
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	// Load current global model_roles
	allRoles, err := h.stores.GlobalConfig.Get(c.Request.Context(), "model_roles")
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to load roles"})
		return
	}
	if allRoles == nil {
		allRoles = models.JSONMap{}
	}

	// Update the specific role
	allRoles[role] = req

	// Persist
	userID := getUserID(c)
	if err := h.stores.GlobalConfig.Set(c.Request.Context(), "model_roles", allRoles, userID); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to save role"})
		return
	}

	c.JSON(http.StatusOK, req)
}

// ── Test Role ──────────────────────────────
// POST /admin/roles/:role/test

func (h *RolesHandler) TestRole(c *gin.Context) {
	role := c.Param("role")
	if !roles.IsValidRole(role) {
		c.JSON(http.StatusBadRequest, gin.H{"error": "unknown role: " + role})
		return
	}

	if role == roles.RoleEmbedding {
		// Test embedding
		result, err := h.resolver.Embed(c.Request.Context(), role, "", nil, []string{"test embedding"})
		if err != nil {
			c.JSON(http.StatusBadGateway, gin.H{"error": err.Error()})
			return
		}
		c.JSON(http.StatusOK, gin.H{
			"status":        "ok",
			"model":         result.Model,
			"provider":      result.ProviderID,
			"dimensions":    len(result.Embeddings[0]),
			"used_fallback": result.UsedFallback,
		})
		return
	}

	// Test completion with a minimal prompt
	result, err := h.resolver.Complete(c.Request.Context(), role, "", nil, []providers.Message{
		{Role: "user", Content: "Say 'ok' and nothing else."},
	})
	if err != nil {
		c.JSON(http.StatusBadGateway, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"status":        "ok",
		"model":         result.Model,
		"provider":      result.ProviderID,
		"content":       result.Content,
		"input_tokens":  result.InputTokens,
		"output_tokens": result.OutputTokens,
		"used_fallback": result.UsedFallback,
	})
}

// ── Team Role Overrides ────────────────────

// ListTeamRoles returns role overrides for a specific team.
// GET /teams/:teamId/roles
func (h *RolesHandler) ListTeamRoles(c *gin.Context) {
	teamID := c.Param("teamId")

	team, err := h.stores.Teams.GetByID(c.Request.Context(), teamID)
	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "team not found"})
		return
	}

	roleOverrides := make(map[string]interface{})
	if team.Settings != nil {
		if raw, ok := team.Settings["model_roles"]; ok {
			if m, ok := raw.(map[string]interface{}); ok {
				roleOverrides = m
			}
		}
	}

	c.JSON(http.StatusOK, roleOverrides)
}

// UpdateTeamRole sets a team role override.
// PUT /teams/:teamId/roles/:role
func (h *RolesHandler) UpdateTeamRole(c *gin.Context) {
	teamID := c.Param("teamId")
	role := c.Param("role")
	if !roles.IsValidRole(role) {
		c.JSON(http.StatusBadRequest, gin.H{"error": "unknown role: " + role})
		return
	}

	var req roles.RoleConfig
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	team, err := h.stores.Teams.GetByID(c.Request.Context(), teamID)
	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "team not found"})
		return
	}

	settings := team.Settings
	if settings == nil {
		settings = models.JSONMap{}
	}

	roleOverrides, _ := settings["model_roles"].(map[string]interface{})
	if roleOverrides == nil {
		roleOverrides = make(map[string]interface{})
	}
	roleOverrides[role] = req
	settings["model_roles"] = roleOverrides

	if err := h.stores.Teams.Update(c.Request.Context(), teamID, map[string]interface{}{
		"settings": settings,
	}); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to save team role"})
		return
	}

	c.JSON(http.StatusOK, req)
}

// DeleteTeamRole removes a team role override (falls back to global).
// DELETE /teams/:teamId/roles/:role
func (h *RolesHandler) DeleteTeamRole(c *gin.Context) {
	teamID := c.Param("teamId")
	role := c.Param("role")

	team, err := h.stores.Teams.GetByID(c.Request.Context(), teamID)
	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "team not found"})
		return
	}

	settings := team.Settings
	if settings == nil {
		c.JSON(http.StatusOK, gin.H{"message": "no override to remove"})
		return
	}

	roleOverrides, _ := settings["model_roles"].(map[string]interface{})
	if roleOverrides != nil {
		delete(roleOverrides, role)
		settings["model_roles"] = roleOverrides
	}

	if err := h.stores.Teams.Update(c.Request.Context(), teamID, map[string]interface{}{
		"settings": settings,
	}); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to remove team role"})
		return
	}

	c.JSON(http.StatusOK, gin.H{"message": "override removed"})
}
