package controller

import (
	"strings"

	"be.ems/lib/log"
	"be.ems/src/framework/constants/common"
	"be.ems/src/framework/i18n"
	"be.ems/src/framework/utils/ctx"
	"be.ems/src/framework/vo"
	"be.ems/src/framework/vo/result"
	"be.ems/src/modules/system/model"
	"be.ems/src/modules/system/service"

	"github.com/gin-gonic/gin"
	"github.com/gin-gonic/gin/binding"
)

// 实例化控制层 SysTenantController 结构体
var NewSysTenant = &SysTenantController{
	sysTenantService: service.NewSysTenantImpl,
}

// 租户信息
//
// PATH /system/tenant
type SysTenantController struct {
	// 租户服务
	sysTenantService service.ISysTenant
}

// 租户列表
//
// GET /list
func (s *SysTenantController) List(c *gin.Context) {
	language := ctx.AcceptLanguage(c)
	var querys struct {
		// 租户ID
		TenantID string `form:"tenantId"`
		// 父租户ID
		ParentID string `form:"parentId" `
		// 租户名称
		TenantName string `form:"tenantName" `
		// 租户状态（0正常 1停用）
		Status string `form:"status"`
	}
	err := c.ShouldBindQuery(&querys)
	if err != nil {
		c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
		return
	}

	// 多语言值转key查询
	if querys.TenantName != "" {
		querys.TenantName = i18n.TFindKeyPrefix(language, "tenant", querys.TenantName)
	}

	SysTenantController := model.SysTenant{
		TenantID:   querys.TenantID,
		ParentID:   querys.ParentID,
		TenantName: querys.TenantName,
		Status:     querys.Status,
	}
	dataScopeSQL := ctx.LoginUserToDataScopeSQL(c, "d", "")
	data := s.sysTenantService.SelectTenantList(SysTenantController, dataScopeSQL)

	// 闭包函数处理多语言
	converI18n := func(language string, arr *[]model.SysTenant) {
		for i := range *arr {
			(*arr)[i].TenantName = i18n.TKey(language, (*arr)[i].TenantName)
		}
	}
	converI18n(language, &data)

	c.JSON(200, result.OkData(data))
}

// 租户信息
//
// GET /:tenantId
func (s *SysTenantController) Info(c *gin.Context) {
	language := ctx.AcceptLanguage(c)
	tenantId := c.Param("tenantId")
	if tenantId == "" {
		c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
		return
	}
	data := s.sysTenantService.SelectTenantById(tenantId)
	if data.TenantID == tenantId {
		// 处理多语言
		data.TenantName = i18n.TKey(language, data.TenantName)
		c.JSON(200, result.OkData(data))
		return
	}
	c.JSON(200, result.Err(nil))
}

// 租户新增
//
// POST /
func (s *SysTenantController) Add(c *gin.Context) {
	language := ctx.AcceptLanguage(c)
	var body model.SysTenant
	err := c.ShouldBindBodyWith(&body, binding.JSON)
	if err != nil || body.TenantID != "" {
		c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
		return
	}

	// 父级ID不为0是要检查
	if body.ParentID != "0" {
		tenantParent := s.sysTenantService.SelectTenantById(body.ParentID)
		if tenantParent.TenantID != body.ParentID {
			// 没有可访问租户数据！
			c.JSON(200, result.ErrMsg(i18n.TKey(language, "tenant.noData")))
			return
		}
		if tenantParent.Status == common.STATUS_NO {
			// 上级租户【%s】停用，不允许新增
			msg := i18n.TTemplate(language, "tenant.errParentStatus", map[string]any{"name": tenantParent.TenantName})
			c.JSON(200, result.ErrMsg(msg))
			return
		}
		if tenantParent.DelFlag == common.STATUS_YES {
			// 上级租户【%s】已删除，不允许新增
			msg := i18n.TTemplate(language, "tenant.errParentDelFlag", map[string]any{"name": tenantParent.TenantName})
			c.JSON(200, result.ErrMsg(msg))
			return
		}
		body.Ancestors = tenantParent.Ancestors + "," + body.ParentID
	} else {
		body.Ancestors = "0"
	}

	// 检查租户名称唯一
	if body.ParentID == "0" {
		uniqueTenantName := s.sysTenantService.CheckUniqueTenantName(body.TenantName, body.ParentID, "")
		if !uniqueTenantName {
			// 租户新增【%s】失败，租户名称已存在
			msg := i18n.TTemplate(language, "tenant.errNameExists", map[string]any{"name": body.TenantName})
			c.JSON(200, result.ErrMsg(msg))
			return
		}
	} else {
		uniqueTenancy := s.sysTenantService.IsUniqueTenancy(body.TenantID, body.TenancyType, body.TenancyKey)
		if !uniqueTenancy {
			// 租赁对象添加失败，租赁对象已存在
			msg := i18n.TTemplate(language, "tenant.errAssetExists", map[string]any{"type": body.TenancyType, "key": body.TenancyKey})
			c.JSON(200, result.ErrMsg(msg))
			return
		}
	}

	body.CreateBy = ctx.LoginUserToUserName(c)
	insertId := s.sysTenantService.InsertTenant(body)
	if insertId != "" {
		// 如果是增加SIM Card类型的，需更新u_sub_user
		if body.TenancyType == "IMSI" && body.Status == "1" {
			affected := s.sysTenantService.UpdateUDMSubTenantID(body.ParentID, body.TenancyKey)
			log.Tracef("body.ParentID=%s, body.TenancyKey=%s, update affected=%v",
				body.ParentID, body.TenancyKey, affected)
		}
		c.JSON(200, result.Ok(nil))
		return
	}

	c.JSON(200, result.Err(nil))
}

// 租户修改
//
// PUT /
func (s *SysTenantController) Edit(c *gin.Context) {
	language := ctx.AcceptLanguage(c)
	var body model.SysTenant
	err := c.ShouldBindBodyWith(&body, binding.JSON)
	if err != nil || body.TenantID == "" {
		c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
		return
	}

	// 上级租户不能选自己
	if body.TenantID == body.ParentID {
		// 租户修改【%s】失败，上级租户不能是自己
		msg := i18n.TTemplate(language, "tenant.errParentID", map[string]any{"name": body.TenantName})
		c.JSON(200, result.ErrMsg(msg))
		return
	}

	// 检查数据是否存在
	tenantInfo := s.sysTenantService.SelectTenantById(body.TenantID)
	if tenantInfo.TenantID != body.TenantID {
		// 没有可访问租户数据！
		c.JSON(200, result.ErrMsg(i18n.TKey(language, "tenant.noData")))
		return
	}
	// 父级ID不为0是要检查
	if body.ParentID != "0" {
		tenantParent := s.sysTenantService.SelectTenantById(body.ParentID)
		if tenantParent.TenantID != body.ParentID {
			// 没有可访问租户数据！
			c.JSON(200, result.ErrMsg(i18n.TKey(language, "tenant.noData")))
			return
		}
	}

	// 检查租户名称唯一
	if body.ParentID == "0" {
		uniqueTenantName := s.sysTenantService.CheckUniqueTenantName(body.TenantName, body.ParentID, body.TenantID)
		if !uniqueTenantName {
			// 租户修改【%s】失败，租户名称已存在
			msg := i18n.TTemplate(language, "tenant.errNameExists", map[string]any{"name": body.TenantName})
			c.JSON(200, result.ErrMsg(msg))
			return
		}
	} else {
		uniqueTenancy := s.sysTenantService.IsUniqueTenancy(body.TenantID, body.TenancyType, body.TenancyKey)
		if !uniqueTenancy {
			// 租赁对象添加失败，租赁对象已存在
			msg := i18n.TTemplate(language, "tenant.errAssetExists", map[string]any{"type": body.TenancyType, "key": body.TenancyKey})
			c.JSON(200, result.ErrMsg(msg))
			return
		}
	}

	// 上级停用需要检查下级是否有在使用
	if body.Status == common.STATUS_NO {
		hasChild := s.sysTenantService.HasChildByTenantId(body.TenantID)
		if hasChild > 0 {
			// 该租户包含未停用的子租户数量：%d
			msg := i18n.TTemplate(language, "tenant.errHasChildUse", map[string]any{"num": hasChild})
			c.JSON(200, result.ErrMsg(msg))
			return
		}
	}

	// 多语言非原始值
	i18nValue := i18n.TKey(language, tenantInfo.TenantName)
	if i18nValue != tenantInfo.TenantName {
		i18n.UpdateKeyValue(language, tenantInfo.TenantName, body.TenantName)
		body.TenantName = tenantInfo.TenantName
	}

	tenantOldInfo := s.sysTenantService.SelectTenantById(body.TenantID)
	body.UpdateBy = ctx.LoginUserToUserName(c)
	rows := s.sysTenantService.UpdateTenant(body)
	if rows > 0 {
		// 如果是更新的是SIM Card类型的，需更新u_sub_user
		// 先清空签约用户原有的租户信息
		if tenantOldInfo.TenancyType == "IMSI" && tenantOldInfo.Status == "1" {
			affected := s.sysTenantService.UpdateUDMSubTenantID("", tenantOldInfo.TenancyKey)
			log.Tracef("tenantOldInfo.ParentID=%s, tenantOldInfo.TenancyKey=%s, update affected=%v",
				tenantOldInfo.ParentID, tenantOldInfo.TenancyKey, affected)
		}
		// 设置新的租户信息
		if body.TenancyType == "IMSI" && body.Status == "1" {
			affected := s.sysTenantService.UpdateUDMSubTenantID(body.ParentID, body.TenancyKey)
			log.Tracef("body.ParentID=%s, body.TenancyKey=%s, update affected=%v",
				body.ParentID, body.TenancyKey, affected)
		}
		c.JSON(200, result.Ok(nil))
		return
	}

	c.JSON(200, result.Err(nil))
}

// 租户删除
//
// DELETE /:tenantId
func (s *SysTenantController) Remove(c *gin.Context) {
	language := ctx.AcceptLanguage(c)
	tenantId := c.Param("tenantId")
	if tenantId == "" {
		c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
		return
	}

	// 检查数据是否存在
	tenant := s.sysTenantService.SelectTenantById(tenantId)
	if tenant.TenantID != tenantId {
		// 没有可访问租户数据！
		c.JSON(200, result.ErrMsg(i18n.TKey(language, "tenant.noData")))
		return
	}

	// 检查是否存在子租户
	hasChild := s.sysTenantService.HasChildByTenantId(tenantId)
	if hasChild > 0 {
		// 不允许删除，存在子租户数：%d
		msg := i18n.TTemplate(language, "tenant.errHasChildUse", map[string]any{"num": hasChild})
		c.JSON(200, result.ErrMsg(msg))
		return
	}

	// 检查是否分配给用户
	existUser := s.sysTenantService.CheckTenantExistUser(tenantId)
	if existUser > 0 {
		// 不允许删除，租户已分配给用户数：%d
		msg := i18n.TTemplate(language, "tenant.errHasUserUse", map[string]any{"num": existUser})
		c.JSON(200, result.ErrMsg(msg))
		return
	}

	tenantOldInfo := s.sysTenantService.SelectTenantById(tenantId)
	rows := s.sysTenantService.DeleteTenantById(tenantId)
	if rows > 0 {
		// 如果是删除的是SIM Card类型的，需删除相关的u_sub_user的租户信息
		if tenantOldInfo.TenancyType == "IMSI" && tenantOldInfo.Status == "1" {
			affected := s.sysTenantService.UpdateUDMSubTenantID("", tenantOldInfo.TenancyKey)
			log.Tracef("tenantOldInfo.ParentID=%s, tenantOldInfo.TenancyKey=%s, update affected=%v",
				tenantOldInfo.ParentID, tenantOldInfo.TenancyKey, affected)
		}
		// 删除成功：%d
		msg := i18n.TTemplate(language, "app.common.deleteSuccess", map[string]any{"num": rows})
		c.JSON(200, result.OkMsg(msg))
		return
	}

	c.JSON(200, result.Err(nil))
}

// 租户列表（排除节点）
//
// GET /list/exclude/:tenantId
func (s *SysTenantController) ExcludeChild(c *gin.Context) {
	language := ctx.AcceptLanguage(c)
	tenantId := c.Param("tenantId")
	if tenantId == "" {
		c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
		return
	}

	dataScopeSQL := ctx.LoginUserToDataScopeSQL(c, "d", "")
	data := s.sysTenantService.SelectTenantList(model.SysTenant{}, dataScopeSQL)

	// 过滤排除节点
	filtered := make([]model.SysTenant, 0)
	for _, tenant := range data {
		hasAncestor := false
		ancestorList := strings.Split(tenant.Ancestors, ",")
		for _, ancestor := range ancestorList {
			if ancestor == tenantId {
				hasAncestor = true
				break
			}
		}
		if !(tenant.TenantID == tenantId || hasAncestor) {
			tenant.TenantName = i18n.TKey(language, tenant.TenantName)
			filtered = append(filtered, tenant)
		}
	}
	c.JSON(200, result.OkData(filtered))
}

// 租户树结构列表
//
// GET /treeSelect
func (s *SysTenantController) TreeSelect(c *gin.Context) {
	language := ctx.AcceptLanguage(c)
	var querys struct {
		// 租户ID
		TenantID string `json:"tenantId"`
		// 父租户ID
		ParentID string `json:"parentId" `
		// 租户名称
		TenantName string `json:"tenantName" `
		// 租户状态（0正常 1停用）
		Status string `json:"status"`
	}
	err := c.ShouldBindQuery(&querys)
	if err != nil {
		c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
		return
	}

	SysTenantController := model.SysTenant{
		TenantID:   querys.TenantID,
		ParentID:   querys.ParentID,
		TenantName: querys.TenantName,
		Status:     querys.Status,
	}
	dataScopeSQL := ctx.LoginUserToDataScopeSQL(c, "d", "")
	tenantTreeSelect := s.sysTenantService.SelectTenantTreeSelect(SysTenantController, dataScopeSQL)

	// 闭包函数处理多语言
	var converI18n func(language string, arr *[]vo.TreeSelect)
	converI18n = func(language string, arr *[]vo.TreeSelect) {
		for i := range *arr {
			(*arr)[i].Label = i18n.TKey(language, (*arr)[i].Label)
			if len((*arr)[i].Children) > 0 {
				converI18n(language, &(*arr)[i].Children)
			}
		}
	}
	converI18n(language, &tenantTreeSelect)

	c.JSON(200, result.OkData(tenantTreeSelect))
}

// 租户树结构列表（指定角色）
//
// GET /roleTenantTreeSelect/:roleId
func (s *SysTenantController) RoleTenantTreeSelect(c *gin.Context) {
	language := ctx.AcceptLanguage(c)
	roleId := c.Param("roleId")
	if roleId == "" {
		c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
		return
	}

	dataScopeSQL := ctx.LoginUserToDataScopeSQL(c, "d", "")
	tenantTreeSelect := s.sysTenantService.SelectTenantTreeSelect(model.SysTenant{}, dataScopeSQL)
	checkedKeys := s.sysTenantService.SelectTenantListByRoleId(roleId)

	// 闭包函数处理多语言
	var converI18n func(language string, arr *[]vo.TreeSelect)
	converI18n = func(language string, arr *[]vo.TreeSelect) {
		for i := range *arr {
			(*arr)[i].Label = i18n.TKey(language, (*arr)[i].Label)
			if len((*arr)[i].Children) > 0 {
				converI18n(language, &(*arr)[i].Children)
			}
		}
	}
	converI18n(language, &tenantTreeSelect)

	c.JSON(200, result.OkData(map[string]any{
		"tenants":     tenantTreeSelect,
		"checkedKeys": checkedKeys,
	}))
}
