package service

import (
	"context"
	"encoding/json"
	"errors"
	"gadmin/config"
	"gadmin/internal/admin/consts"
	"gadmin/internal/admin/forms"
	"gadmin/internal/gorm/model"
	"gadmin/internal/gorm/query"
	"gadmin/utility/serializer"
	"github.com/gin-gonic/gin"
	"github.com/sirupsen/logrus"
	"github.com/spf13/cast"
	"gorm.io/gorm"
	"time"
)

// AdminRole 后台角色
var AdminRole = new(sAdminRole)

type sAdminRole struct{}

func (s *sAdminRole) List(ctx *gin.Context, req forms.AdminRoleListReq) serializer.Response {
	var (
		q            = query.Use(config.AdminDB).AdminRole
		m            = q.WithContext(ctx)
		offset int64 = 0
		models forms.UserAccountListRes
		lists  []*forms.AdminRoleListModel
	)

	m = m.Order(q.Sort).Order(q.ID.Desc())

	req.Page, req.PerPage, offset = forms.CalculatePage(req.Page, req.PerPage)

	count, err := m.Count()
	if err != nil {
		return serializer.Err(consts.CodeParamErr, "查询出错 count", err)
	}

	if count > 0 {
		if err = m.Limit(int(req.PerPage)).Offset(int(offset)).Scan(&lists); err != nil {
			return serializer.Err(consts.CodeParamErr, "查询出错 lists", err)
		}
	}

	for _, v := range lists {
		systemIds := make([]int32, 0)
		if err := json.Unmarshal([]byte(cast.ToString(v.Systems)), &systemIds); err != nil {
			return serializer.Err(consts.CodeParamErr, "格式化出错 Systems", err)
		}
		v.Systems = systemIds
		permissionsMap := make(map[int32][]int32)
		pagesMap := make(map[int32][]int32)
		for _, sid := range systemIds {
			if _, ok := config.LogDBGroup[sid]; !ok {
				continue
			}
			logDB := query.Use(config.LogDBGroup[sid])
			pq := logDB.AdminRolePermission
			mq := logDB.AdminRoleMenu
			// 查询该角色各系统下的权限
			permissionIds := make([]int32, 0)
			if err := pq.Where(pq.RoleID.Eq(int32(v.ID))).Pluck(pq.PermissionID, &permissionIds); err != nil {
				return serializer.Err(consts.CodeParamErr, "查询出错 permissionsModels", err)
			}
			if _, ok := permissionsMap[sid]; ok {
				permissionsMap[sid] = append(permissionsMap[sid], permissionIds...)
			} else {
				permissionsMap[sid] = permissionIds
			}
			// 查询该角色各系统下的页面
			pageIds := make([]int32, 0)
			if err := mq.Where(mq.RoleID.Eq(int32(v.ID))).Pluck(mq.PageID, &pageIds); err != nil {
				return serializer.Response{}
			}
			if _, ok := pagesMap[sid]; ok {
				pagesMap[sid] = append(pagesMap[sid], pageIds...)
			} else {
				pagesMap[sid] = pageIds
			}
		}
		v.Permissions = permissionsMap
		v.Pages = pagesMap
	}

	models.List = lists
	models.Page = req.Page
	models.PerPage = req.PerPage
	models.PageCount = (count + req.PerPage - 1) / req.PerPage

	return serializer.Suc(models)
}

func (s *sAdminRole) Edit(ctx *gin.Context, req forms.AdminRoleEditReq) serializer.Response {

	q := query.Use(config.AdminDB).AdminRole
	uq := query.Use(config.AdminDB).AdminUser

	logrus.Warnf("req:%+v", req)

	type systemOperation struct {
		Permissions []*model.AdminRolePermission
		Pages       []*model.AdminRoleMenu
	}
	systemOperations := make(map[int32]*systemOperation)

	for sysId, menus := range req.Pages {
		if _, ok := systemOperations[sysId]; !ok {
			systemOperations[sysId] = &systemOperation{
				Permissions: make([]*model.AdminRolePermission, 0),
				Pages:       make([]*model.AdminRoleMenu, 0),
			}
		}
		for _, menu := range menus {
			systemOperations[sysId].Pages = append(systemOperations[sysId].Pages, &model.AdminRoleMenu{
				SystemID: sysId,
				RoleID:   int32(req.ID),
				PageID:   menu,
			})
		}
	}

	for sysId, permissions := range req.Permissions {
		if _, ok := systemOperations[sysId]; !ok {
			systemOperations[sysId] = &systemOperation{
				Permissions: make([]*model.AdminRolePermission, 0),
				Pages:       make([]*model.AdminRoleMenu, 0),
			}
		}
		for _, id := range permissions {
			systemOperations[sysId].Permissions = append(systemOperations[sysId].Permissions, &model.AdminRolePermission{
				SystemID:     sysId,
				RoleID:       int32(req.ID),
				PermissionID: id,
			})
		}
	}

	systems, err := json.Marshal(req.Systems)
	if err != nil {
		return serializer.Err(consts.CodeParamErr, "格式化出错 Systems:", err)
	}
	// 修改
	if req.ID > 0 {
		update := &model.AdminRole{
			Name:      req.Name,
			Key:       req.Key,
			Sort:      req.Sort,
			Remark:    req.Remark,
			Status:    req.Status,
			Systems:   string(systems),
			UpdatedAt: time.Now(),
		}
		// 修改角色基本信息
		_, err := q.Where(q.ID.Eq(req.ID)).Updates(update)
		if err != nil {
			return serializer.Err(consts.CodeDBError, "更新出错", err)
		}
		// 各系统权限、页面处理
		for sysId, it := range systemOperations {
			if _, ok := config.LogDBGroup[sysId]; !ok {
				continue
			}
			logDB := query.Use(config.LogDBGroup[sysId])
			mq := logDB.AdminRoleMenu
			pq := logDB.AdminRolePermission
			queryTx := logDB.Begin()
			// 删除旧的菜单权限
			if _, err := queryTx.AdminRoleMenu.Where(mq.RoleID.Eq(int32(req.ID))).Delete(); err != nil {
				queryTx.Rollback()
				return serializer.Err(consts.CodeDBError, "更新出错", err)
			}
			// 插入新的菜单权限
			if err := queryTx.AdminRoleMenu.Create(it.Pages...); err != nil {
				queryTx.Rollback()
				return serializer.Err(consts.CodeDBError, "更新出错", err)
			}
			// 删除旧的操作权限
			if _, err := queryTx.AdminRolePermission.Where(pq.RoleID.Eq(int32(req.ID))).Delete(); err != nil {
				queryTx.Rollback()
				return serializer.Err(consts.CodeDBError, "更新出错", err)
			}
			// 插入新的操作权限
			if err := queryTx.AdminRolePermission.Create(it.Permissions...); err != nil {
				queryTx.Rollback()
				return serializer.Err(consts.CodeDBError, "更新出错", err)
			}
			queryTx.Commit()
		}

		// 查询该角色下的用户，清空token
		users, _ := query.Use(config.AdminDB).AdminUser.Where(uq.RoleID.Eq(int32(req.ID))).Find()
		for _, user := range users {
			config.TokenRedis.Del(config.GetUserTokenKey(user.ID))
		}
		return serializer.Suc(nil)
	}

	// 新增
	create := &model.AdminRole{
		Name:      req.Name,
		Key:       req.Key,
		Sort:      req.Sort,
		Systems:   string(systems),
		Remark:    req.Remark,
		Status:    req.Status,
		UpdatedAt: time.Now(),
		CreatedAt: time.Now(),
	}

	if err := q.WithContext(ctx).Create(create); err != nil {
		logrus.Error(err)
		return serializer.Err(consts.CodeDBError, "更新出错", err)
	}
	// 插入新的菜单权限
	for sysId, it := range systemOperations {
		if _, ok := config.LogDBGroup[sysId]; !ok {
			continue
		}
		logDB := query.Use(config.LogDBGroup[sysId])
		queryTx := logDB.Begin()
		for i := range it.Pages {
			it.Pages[i].RoleID = int32(create.ID)
		}
		for i := range it.Permissions {
			it.Permissions[i].RoleID = int32(create.ID)
		}
		// 插入页面权限
		if err := queryTx.AdminRoleMenu.Create(it.Pages...); err != nil {
			logrus.Error(err)
			queryTx.Rollback()
			return serializer.Err(consts.CodeDBError, "更新出错", err)
		}
		// 插入操作权限
		if err := queryTx.AdminRolePermission.Create(it.Permissions...); err != nil {
			logrus.Error(err)
			queryTx.Rollback()
			return serializer.Err(consts.CodeDBError, "更新出错", err)
		}
		queryTx.Commit()
	}

	return serializer.Suc(nil)
}

func (s *sAdminRole) GetRole(ctx *gin.Context, req forms.AdminRoleReq) (*model.AdminRole, error) {
	var (
		q = query.Use(config.AdminDB).AdminRole
		m = q.WithContext(ctx)
	)
	result, err := m.Where(q.ID.Eq(req.ID)).First()
	if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
		return nil, err
	}
	return result, nil
}

func (s *sAdminRole) GetAllSystem() ([]*model.AdminSystem, error) {
	var (
		q = query.Use(config.AdminDB).AdminSystem
	)
	systems, err := q.Find()
	if err != nil {
		logrus.Error(err)
	}
	return systems, nil
}

func (s *sAdminRole) GetOperation(systemId int32) ([]*model.AdminOperation, error) {
	if _, ok := config.LogDBGroup[systemId]; !ok {
		logrus.Warnf("系统不存在systemId:%v", systemId)
		return []*model.AdminOperation{}, nil
	}
	q := query.Use(config.LogDBGroup[systemId]).AdminOperation

	//q := query.Use(config.AdminDB).AdminMenu
	m := q.WithContext(context.Background())
	operations, err := m.Find()
	if err != nil {
		logrus.Error(err)
		return nil, err
	}
	//retMenus := handleMenus(operations)
	return operations, nil
}
