package handlers

// persona_groups.go — Persona group (roster template) CRUD (v0.23.2)
//
// v0.29.0: Raw SQL replaced with PersonaGroupStore methods.

import (
	"net/http"
	"strings"

	"github.com/gin-gonic/gin"

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

type PersonaGroupHandler struct {
	stores store.Stores
}

func NewPersonaGroupHandler(s store.Stores) *PersonaGroupHandler {
	return &PersonaGroupHandler{stores: s}
}

// ── List ────────────────────────────────────────

func (h *PersonaGroupHandler) List(c *gin.Context) {
	userID := getUserID(c)

	groups, err := h.stores.PersonaGroups.List(c.Request.Context(), userID)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to list groups"})
		return
	}

	for i := range groups {
		members, _ := h.stores.PersonaGroups.ListMembers(c.Request.Context(), groups[i].ID)
		groups[i].Members = members
	}

	c.JSON(http.StatusOK, gin.H{"data": groups})
}

// ── Get ─────────────────────────────────────────

func (h *PersonaGroupHandler) Get(c *gin.Context) {
	userID := getUserID(c)
	id := c.Param("id")

	g, err := h.stores.PersonaGroups.Get(c.Request.Context(), id, userID)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to get group"})
		return
	}
	if g == nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "group not found"})
		return
	}

	members, _ := h.stores.PersonaGroups.ListMembers(c.Request.Context(), g.ID)
	if members == nil {
		members = []models.PersonaGroupMember{}
	}
	g.Members = members

	c.JSON(http.StatusOK, g)
}

// ── Create ──────────────────────────────────────

func (h *PersonaGroupHandler) Create(c *gin.Context) {
	userID := getUserID(c)

	var req struct {
		Name        string `json:"name" binding:"required,min=1,max=100"`
		Description string `json:"description"`
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	g := &models.PersonaGroup{
		Name:        strings.TrimSpace(req.Name),
		Description: req.Description,
		OwnerID:     userID,
		Scope:       "personal",
	}

	if err := h.stores.PersonaGroups.Create(c.Request.Context(), g); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to create group"})
		return
	}

	g.Members = []models.PersonaGroupMember{}
	c.JSON(http.StatusCreated, g)
}

// ── Update ──────────────────────────────────────

func (h *PersonaGroupHandler) Update(c *gin.Context) {
	userID := getUserID(c)
	id := c.Param("id")

	var req struct {
		Name        *string `json:"name"`
		Description *string `json:"description"`
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	// Verify ownership
	ownerID, err := h.stores.PersonaGroups.GetOwnerID(c.Request.Context(), id)
	if err != nil || ownerID == "" {
		c.JSON(http.StatusNotFound, gin.H{"error": "group not found"})
		return
	}
	if ownerID != userID {
		c.JSON(http.StatusForbidden, gin.H{"error": "not your group"})
		return
	}

	fields := map[string]interface{}{}
	if req.Name != nil {
		fields["name"] = strings.TrimSpace(*req.Name)
	}
	if req.Description != nil {
		fields["description"] = *req.Description
	}
	if len(fields) > 0 {
		_ = h.stores.PersonaGroups.Update(c.Request.Context(), id, fields)
	}

	c.JSON(http.StatusOK, gin.H{"ok": true})
}

// ── Delete ──────────────────────────────────────

func (h *PersonaGroupHandler) Delete(c *gin.Context) {
	userID := getUserID(c)
	id := c.Param("id")

	n, err := h.stores.PersonaGroups.Delete(c.Request.Context(), id, userID)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "delete failed"})
		return
	}
	if n == 0 {
		c.JSON(http.StatusNotFound, gin.H{"error": "group not found"})
		return
	}
	c.JSON(http.StatusOK, gin.H{"ok": true})
}

// ── Add Member ──────────────────────────────────

func (h *PersonaGroupHandler) AddMember(c *gin.Context) {
	userID := getUserID(c)
	groupID := c.Param("id")

	var req struct {
		PersonaID string `json:"persona_id" binding:"required"`
		IsLeader  bool   `json:"is_leader"`
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	// Verify ownership
	ownerID, err := h.stores.PersonaGroups.GetOwnerID(c.Request.Context(), groupID)
	if err != nil || ownerID != userID {
		c.JSON(http.StatusForbidden, gin.H{"error": "not your group"})
		return
	}

	if err := h.stores.PersonaGroups.AddMember(c.Request.Context(), groupID, req.PersonaID, req.IsLeader); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to add member"})
		return
	}

	c.JSON(http.StatusCreated, gin.H{"ok": true})
}

// ── Remove Member ───────────────────────────────

func (h *PersonaGroupHandler) RemoveMember(c *gin.Context) {
	userID := getUserID(c)
	groupID := c.Param("id")
	memberID := c.Param("memberId")

	ownerID, err := h.stores.PersonaGroups.GetOwnerID(c.Request.Context(), groupID)
	if err != nil || ownerID != userID {
		c.JSON(http.StatusForbidden, gin.H{"error": "not your group"})
		return
	}

	_ = h.stores.PersonaGroups.RemoveMember(c.Request.Context(), memberID, groupID)
	c.JSON(http.StatusOK, gin.H{"ok": true})
}
