package logic

import (
	"fusenapi/utils/auth"
	"fusenapi/utils/basic"
	"fusenapi/utils/ldap_lib"
	"github.com/go-ldap/ldap/v3"
	"sort"
	"strings"

	"context"

	"fusenapi/server/ldap-admin/internal/svc"
	"fusenapi/server/ldap-admin/internal/types"

	"github.com/zeromicro/go-zero/core/logx"
)

type GetLdapOrganizationsLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewGetLdapOrganizationsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetLdapOrganizationsLogic {
	return &GetLdapOrganizationsLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

// 处理进入前逻辑w,r
// func (l *GetLdapOrganizationsLogic) BeforeLogic(w http.ResponseWriter, r *http.Request) {
// }
type DNItem struct {
	Attribute map[string]interface{} `json:"attribute"`
	HasMember bool                   `json:"has_member"` //是否有成员
	DN        string                 `json:"dn"`
	ParentDN  string                 `json:"parent_dn"`
	Sort      int                    `json:"sort"`
	Child     []*DNItem              `json:"child"`
}

func (l *GetLdapOrganizationsLogic) GetLdapOrganizations(req *types.Request, userinfo *auth.UserInfo) (resp *basic.Response) {
	//从ldap获取组织架构数据
	rootCn := strings.Split(l.svcCtx.Config.Ldap.RootDN, ",")
	if len(rootCn) == 0 {
		return resp.SetStatusWithMessage(basic.CodeServiceErr, "root用户DN未设置")
	}
	ldapServer := ldap_lib.NewLdap(l.svcCtx.Ldap, l.svcCtx.Config.Ldap.BaseDN, l.svcCtx.Config.Ldap.RootDN)
	peopleDNSlice := strings.Split(l.svcCtx.Config.Ldap.PeopleGroupDN, ",")
	if len(peopleDNSlice) <= 1 {
		return resp.SetStatusWithMessage(basic.CodeServiceErr, "基础用户组的DN未配置")
	}
	filter := "(|(&(objectClass=groupOfUniqueNames)(objectClass=top))(objectClass=organization))"
	fields := []string{"businessCategory", "dn", "uniqueMember"}
	searchResult, err := ldapServer.Search(l.svcCtx.Config.Ldap.BaseDN, ldap.ScopeWholeSubtree, filter, fields, nil)
	if err != nil {
		return resp.SetStatusWithMessage(basic.CodeServiceErr, "查询失败:"+err.Error())
	}
	mapDN := make(map[string]*DNItem)
	sortNum := 0
	//每个DN存入map
	for _, v := range searchResult.Entries {
		sortNum++
		attribute := make(map[string]interface{})
		hasMember := false
		for _, attr := range v.Attributes {
			//判断是否有成员(不包含root用户所以判断大于1)
			if attr.Name == "uniqueMember" && len(attr.Values) > 1 {
				hasMember = true
				continue
			}
			attribute[attr.Name] = strings.Join(attr.Values, ",")
		}
		mapDN[v.DN] = &DNItem{
			DN:        v.DN,
			ParentDN:  "",
			HasMember: hasMember,
			Attribute: attribute,
			Sort:      sortNum,
			Child:     make([]*DNItem, 0, 100),
		}
	}
	//组织树形层级关系
	minLevel := 0
	for dn, v := range mapDN {
		sl := strings.Split(dn, ",")
		lensl := len(sl)
		if lensl < minLevel || minLevel == 0 {
			minLevel = lensl
		}
		//没有父级
		if lensl <= 1 {
			continue
		}
		//有父级
		parentDN := strings.Join(sl[1:], ",")
		if parent, ok := mapDN[parentDN]; ok {
			v.ParentDN = parentDN
			parent.Child = append(parent.Child, v)
			//排序
			sort.Slice(parent.Child, func(i, j int) bool {
				return parent.Child[i].Sort < parent.Child[j].Sort
			})
		}
	}
	//只获取最顶层
	list := make([]interface{}, 0, len(mapDN))
	for dn, v := range mapDN {
		sl := strings.Split(dn, ",")
		if len(sl) == minLevel {
			list = append(list, v)
		}
	}
	return resp.SetStatusWithMessage(basic.CodeOK, "", list)
}

// 处理逻辑后 w,r 如:重定向, resp 必须重新处理
// func (l *GetLdapOrganizationsLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) {
// // httpx.OkJsonCtx(r.Context(), w, resp)
// }