package service

import (
	"SSO/models"
	"fmt"

	"github.com/jinzhu/gorm"
)

func getAllOriginPurviews(appType int) ([]*models.Purview, error) {
	var purviews []*models.Purview
	getPurviewErr := readUserDb.Model(models.Purview{}).Where("module = ? AND status = 1", appType).Order("listorder asc").Order("id asc").Find(&purviews).Error
	if getPurviewErr != nil {
		if getPurviewErr == gorm.ErrRecordNotFound {
			return nil, nil
		} else {
			return nil, getPurviewErr
		}
	}
	return purviews, nil
}

func GetAllPurviewsProcessed(appType int) ([]*models.Purview, error) {
	originPurviews, getPurviewErr := getAllOriginPurviews(appType)
	if getPurviewErr != nil {
		return nil, getPurviewErr
	}
	return processPurviews2Tree(originPurviews), nil
}

// 加工这些规则：树形化
// 正确结果的前提是 originPurviews 以 parentid asc 排好序了的
func processPurviews2Tree(originPurviews []*models.Purview) []*models.Purview {
	processedPurviews := make([]*models.Purview, 0)
	pid_childs := make(map[int][]*models.Purview)
	for _, purview := range originPurviews {
		// warning：下面这个算法只适用最多两层树形结构的菜单，对于两层以上的会丢失掉第三层及其以下的节点
		// 因为取出 originPurviews 的时候已经排过序了，所以顶级节点肯定最先处理，不需要担心子节点比父节点先处理
		if purview.Parentid == 0 {
			processedPurviews = append(processedPurviews, purview)
		} else {
			childs := pid_childs[purview.Parentid]
			if pid_childs[purview.Parentid] == nil {
				childs = make([]*models.Purview, 0)
			}
			childs = append(childs, purview)
			pid_childs[purview.Parentid] = childs
		}
	}

	for _, proPurview := range processedPurviews {
		proPurview.Childs = pid_childs[proPurview.Id]
	}

	return processedPurviews
}

func GetSuperAdminUsersPurviewTreeAndUrlfors(appType int) ([]string, []*models.Purview, error) {
	originPurviews, getPurviewErr := getAllOriginPurviews(appType)
	if getPurviewErr != nil {
		return nil, nil, getPurviewErr
	}
	urlfors, processedPurviews := getUrlforsAndProcessPurviews2Tree(originPurviews)
	return urlfors, processedPurviews, nil
}

func GetGeneralAdminUsersPurviewTreeAndUrlfors(adminUserID int, appId int) ([]string, []*models.Purview, error) {
	rows, err := readUserDb.Raw("SELECT p.purview_ids AS pids FROM sgj_user_admin_role AS a_r, sgj_user_role_purview AS p WHERE a_r.admin_user_id = ? AND  a_r.app_id = ? AND a_r.role_id = p.role_id AND a_r.status = 1 AND p.`status` = 1;", adminUserID, appId).Rows()
	defer rows.Close()
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			return make([]string, 0), make([]*models.Purview, 0), nil
		} else {
			return nil, nil, err
		}
	}
	pids := ""
	if rows.Next() {
		rows.Scan(&pids)
	}

	if len(pids) == 0 {
		return make([]string, 0), make([]*models.Purview, 0), nil
	} else {
		var originPurviews []*models.Purview
		getPurviewErr := readUserDb.Model(&models.Purview{}).Where(fmt.Sprintf("id in (%v) and status = 1", pids)).Order("listorder asc").Order("id asc").Find(&originPurviews).Error
		if getPurviewErr != nil {
			if err == gorm.ErrRecordNotFound {
				return make([]string, 0), make([]*models.Purview, 0), nil
			} else {
				return nil, nil, err
			}
		} else {
			urlfors, processedPurviews := getUrlforsAndProcessPurviews2Tree(originPurviews)
			return urlfors, processedPurviews, nil
		}
	}
}

// 加工这些规则：树形化；以及从中取出不为空的 urlfor
// 正确结果的前提是 originPurviews 以 parentid asc 排好序了的
func getUrlforsAndProcessPurviews2Tree(originPurviews []*models.Purview) ([]string, []*models.Purview) {
	processedPurviews := make([]*models.Purview, 0)
	pid_childs := make(map[int][]*models.Purview)
	urlfors := make([]string, 0, len(originPurviews))
	for _, purview := range originPurviews {
		if len(purview.Urlfor) != 0 {
			urlfors = append(urlfors, purview.Urlfor)
		}

		// warning：下面这个算法只适用最多两层树形结构的菜单，对于两层以上的会丢失掉第三层及其以下的节点
		// 因为取出 originPurviews 的时候已经排过序了，所以顶级节点肯定最先处理，不需要担心子节点比父节点先处理
		if purview.Parentid == 0 {
			processedPurviews = append(processedPurviews, purview)
		} else {
			childs := pid_childs[purview.Parentid]
			if pid_childs[purview.Parentid] == nil {
				childs = make([]*models.Purview, 0)
			}
			childs = append(childs, purview)
			pid_childs[purview.Parentid] = childs
		}
	}

	for _, proPurview := range processedPurviews {
		proPurview.Childs = pid_childs[proPurview.Id]
	}

	return urlfors, processedPurviews
}
