package service

import (
	"encoding/json"
	"fmt"

	"github.com/go-ldap/ldap/v3"

	"be.ems/src/framework/config"
	"be.ems/src/framework/constants"
	"be.ems/src/framework/token"
	"be.ems/src/framework/utils/parse"
	"be.ems/src/modules/auth/model"
	systemModelVo "be.ems/src/modules/system/model/vo"
)

// ByLDAP 登录创建用户信息
func (s *Account) ByLDAP(body model.LoginSourceBody) (token.UserInfo, error) {
	info := token.UserInfo{}
	rows := s.sysLogSourceService.FindByActive(body.UID)
	if len(rows) != 1 {
		return info, fmt.Errorf("ldap auth source not exist")
	}
	item := rows[0]
	if item.Config == "" {
		return info, fmt.Errorf("ldap auth source config is empty")
	}
	var source systemModelVo.SysLoginSourceLDAP
	if err := json.Unmarshal([]byte(item.Config), &source); err != nil {
		return info, err
	}

	// 校验LDAP用户
	err := ldapAuth(source, body.Username, body.Password)
	if err != nil {
		return info, err
	}

	// 查询用户登录账号
	sysUser := s.sysUserService.FindByUserName(body.Username, item.Type, item.UID)
	if sysUser.UserId == 0 || sysUser.UserName == "" {
		sysUser = s.initLoginSourceUser(item.UID, item.Type, body.Username, body.Password)
	}
	if sysUser.UserId == 0 || sysUser.UserName != body.Username {
		return info, fmt.Errorf("login.errNameOrPasswd")
	}
	if sysUser.DelFlag == constants.STATUS_YES {
		return info, fmt.Errorf("login.errDelFlag")
	}
	if sysUser.StatusFlag == constants.STATUS_NO {
		return info, fmt.Errorf("login.errStatus")
	}

	// 登录用户信息
	info.UserId = sysUser.UserId
	info.DeptId = sysUser.DeptId
	info.User = sysUser
	// 用户权限组标识
	if config.IsSystemUser(sysUser.UserId) {
		info.Permissions = []string{constants.SYS_PERMISSION_SYSTEM}
	} else {
		perms := s.sysMenuService.FindPermsByUserId(sysUser.UserId)
		info.Permissions = parse.RemoveDuplicates(perms)
	}
	return info, nil
}

// ldapAuth 校验LDAP用户
func ldapAuth(source systemModelVo.SysLoginSourceLDAP, username, password string) error {
	// 连接LDAP
	l, err := ldap.DialURL(source.URL)
	if err != nil {
		return err
	}
	defer l.Close()

	// 绑定DN校验
	if source.BindDN != "" && source.BindPassword != "" {
		if err := l.Bind(source.BindDN, source.BindPassword); err != nil {
			return fmt.Errorf("ldap user bind %s", err)
		}
	}

	// 搜索用户
	searchRequest := ldap.NewSearchRequest(
		source.BaseDN,
		ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
		fmt.Sprintf(source.UserFilter, ldap.EscapeFilter(username)),
		[]string{"dn", "uid"},
		nil,
	)
	sr, err := l.Search(searchRequest)
	if err != nil {
		return fmt.Errorf("ldap user search %s", err)
	}
	// for _, entry := range sr.Entries {
	// 	fmt.Printf("%s ==== %v\n", entry.DN, entry.GetAttributeValue("uid"))
	// }
	if len(sr.Entries) != 1 {
		return fmt.Errorf("ldap user does not exist or too many entries returned")
	}

	// 校验密码
	if err = l.Bind(sr.Entries[0].DN, password); err != nil {
		return fmt.Errorf("ldap user bind %s", err)
	}
	return nil
}
