package handler

import (
	"net/http"
	"strings"

	"github.com/gin-gonic/gin"
	"github.com/sundynix/sundynix-gateway/internal/store"
)

// 租户自助管理（薄 Web 面入口）：成员名册/邀请/改角色/移除 + 自助建组织。
//
// 与 /admin/tenants/:id/* 平台超管口径的关键区别：
//   - 作用于「当前活跃租户」——租户 id 取请求 ctx（TenantContext 注入），天然只能管自己
//     所在的租户，不接受路径里的任意租户 id；
//   - 角色门槛由路由上的 RequireTenantRole 把守（看 ≥viewer、写 ≥admin），真闸在后端；
//   - owner 保护（不可改角色/不可移除）在 store 层已实现，这里不重写；
//   - 自助版额外挡两个平台超管可为所欲为、租户 admin 不该有的动作：邀请为 owner、
//     以及借 AddMemberByEmail 的 upsert 语义给既有 owner「重新邀请」实现降权。

// TenantMembers: GET /api/v1/tenants/current/members —— 当前租户成员名册（任何成员可看）。
func (h *Handler) TenantMembers(c *gin.Context) {
	rows, err := h.db.ListMembers(c.Request.Context(), tenantID(c))
	if err != nil {
		c.JSON(http.StatusBadGateway, gin.H{"error": err.Error()})
		return
	}
	c.JSON(http.StatusOK, gin.H{"members": rows})
}

// TenantAddMember: POST /api/v1/tenants/current/members {email, role} —— 邀请已注册用户加入。
func (h *Handler) TenantAddMember(c *gin.Context) {
	var b struct {
		Email string `json:"email"`
		Role  string `json:"role"`
	}
	if err := c.ShouldBindJSON(&b); err != nil || strings.TrimSpace(b.Email) == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "email 必填"})
		return
	}
	if b.Role == "" {
		b.Role = store.RoleMember
	}
	if b.Role == store.RoleOwner {
		c.JSON(http.StatusBadRequest, gin.H{"error": "不能邀请为 owner（owner 须转让）"})
		return
	}
	ctx := c.Request.Context()
	tid := tenantID(c)
	// AddMemberByEmail 是 upsert：对既有成员会覆盖角色。对 owner 这等于「重新邀请即降权」，
	// 平台超管口径无所谓，租户自助必须挡——否则 admin 能借邀请把 owner 拉下马。
	email := strings.ToLower(strings.TrimSpace(b.Email))
	if members, err := h.db.ListMembers(ctx, tid); err == nil {
		for _, m := range members {
			if strings.ToLower(m.Email) == email && m.Role == store.RoleOwner {
				c.JSON(http.StatusBadRequest, gin.H{"error": "对方是 owner，不能通过邀请改其角色"})
				return
			}
		}
	}
	m, err := h.db.AddMemberByEmail(ctx, tid, email, b.Role)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	c.JSON(http.StatusOK, gin.H{"member": m})
}

// TenantSetMemberRole: PUT /api/v1/tenants/current/members/:uid {role} —— 改成员角色。
func (h *Handler) TenantSetMemberRole(c *gin.Context) {
	var b struct {
		Role string `json:"role"`
	}
	if err := c.ShouldBindJSON(&b); err != nil || b.Role == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "role 必填"})
		return
	}
	// owner 不可被改/不可被授予，store.SetMemberRole 已拦，这里透传其错误文案即可。
	if err := h.db.SetMemberRole(c.Request.Context(), tenantID(c), c.Param("uid"), b.Role); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	c.JSON(http.StatusOK, gin.H{"status": "ok"})
}

// TenantRemoveMember: DELETE /api/v1/tenants/current/members/:uid —— 软移除成员（owner 拦在 store）。
func (h *Handler) TenantRemoveMember(c *gin.Context) {
	if err := h.db.RemoveMember(c.Request.Context(), tenantID(c), c.Param("uid")); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	c.JSON(http.StatusOK, gin.H{"status": "ok"})
}

// CreateMyTenant: POST /api/v1/me/tenants {name} —— 自助建组织：创建者即 owner，并切为活跃租户。
// slug 用雪花 id 生成（org-<id>），不让用户自定义——slug 全局唯一，自助场景撞名只会添乱。
func (h *Handler) CreateMyTenant(c *gin.Context) {
	var b struct {
		Name string `json:"name"`
	}
	if err := c.ShouldBindJSON(&b); err != nil || strings.TrimSpace(b.Name) == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "name 必填"})
		return
	}
	ctx := c.Request.Context()
	uid := userID(c)
	t, err := h.db.CreateTenant(ctx, strings.TrimSpace(b.Name), "org-"+store.NewID(), "free")
	if err != nil {
		c.JSON(http.StatusBadGateway, gin.H{"error": err.Error()})
		return
	}
	if err := h.db.AddMember(ctx, t.ID, uid, store.RoleOwner); err != nil {
		// 组织已建但 owner 没挂上 = 一个没人能管的孤儿租户，必须当错误暴露而不是带 warn 返回 200。
		c.JSON(http.StatusBadGateway, gin.H{"error": "组织已创建但设置 owner 失败：" + err.Error()})
		return
	}
	// 建完即切入（和桌面端建空间的体验一致）；切换失败不致命，前端下次切换即可。
	_ = h.db.SetActiveTenant(ctx, uid, t.ID)
	c.JSON(http.StatusOK, gin.H{
		"tenant": gin.H{"id": t.ID, "name": t.Name, "slug": t.Slug, "plan": t.Plan, "status": t.Status},
		"active": t.ID,
	})
}
