package admin_role

import (
    "context"

    "bdqr-server/app/main/api/internal/svc"
    "bdqr-server/app/main/api/internal/types"
    "bdqr-server/app/main/model"
    "bdqr-server/common/xerr"

    "github.com/pkg/errors"
    "github.com/samber/lo"
    "github.com/zeromicro/go-zero/core/logx"
    "github.com/zeromicro/go-zero/core/stores/sqlx"
    "github.com/google/uuid"
)

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

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

func (l *UpdateRoleLogic) UpdateRole(req *types.UpdateRoleReq) (resp *types.UpdateRoleResp, err error) {
	// 检查角色是否存在
	role, err := l.svcCtx.AdminRoleModel.FindOne(l.ctx, req.Id)
	if err != nil {
		if errors.Is(err, model.ErrNotFound) {
			return nil, errors.Wrapf(xerr.NewErrMsg("角色不存在"), "更新角色失败, 角色不存在err: %v", err)
		}
		return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新角色失败err: %v", err)
	}

	// 检查角色编码是否重复
	if req.RoleCode != nil && *req.RoleCode != role.RoleCode {
		roleModel, err := l.svcCtx.AdminRoleModel.FindOneByRoleCode(l.ctx, *req.RoleCode)
		if err != nil {
			return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新角色失败err: %v", err)
		}
		if roleModel != nil {
			return nil, errors.Wrapf(xerr.NewErrMsg("角色编码已存在"), "更新角色失败, 角色编码已存在err: %v", err)
		}
	}

	// 更新角色信息
	if req.RoleName != nil {
		role.RoleName = *req.RoleName
	}
	if req.RoleCode != nil {
		role.RoleCode = *req.RoleCode
	}
	if req.Description != nil {
		role.Description = *req.Description
	}
	if req.Status != nil {
		role.Status = *req.Status
	}
	if req.Sort != nil {
		role.Sort = *req.Sort
	}

	// 使用事务更新角色和关联菜单
	err = l.svcCtx.AdminRoleModel.Trans(l.ctx, func(ctx context.Context, session sqlx.Session) error {
		// 更新角色
		_, err = l.svcCtx.AdminRoleModel.Update(ctx, session, role)
		if err != nil {
			return err
		}
		if req.MenuIds != nil {
			// 1. 获取当前关联的菜单ID
			builder := l.svcCtx.AdminRoleMenuModel.SelectBuilder().
				Where("role_id = ?", req.Id)
			currentMenus, err := l.svcCtx.AdminRoleMenuModel.FindAll(ctx, builder, "id ASC")
			if err != nil {
				return err
			}

			// 2. 转换为map便于查找
			currentMenuMap := make(map[string]*model.AdminRoleMenu)
			for _, menu := range currentMenus {
				currentMenuMap[menu.MenuId] = menu
			}

			// 3. 检查新的菜单ID是否存在
			for _, menuId := range req.MenuIds {
				exists, err := l.svcCtx.AdminMenuModel.FindOne(ctx, menuId)
				if err != nil || exists == nil {
					return errors.Wrapf(xerr.NewErrMsg("菜单不存在"), "菜单ID: %s", menuId)
				}
			}

			// 4. 找出需要删除和新增的关联
			var toDelete []*model.AdminRoleMenu
			var toInsert []string

			// 需要删除的：当前存在但新列表中没有的
			for menuId, roleMenu := range currentMenuMap {
				if !lo.Contains(req.MenuIds, menuId) {
					toDelete = append(toDelete, roleMenu)
				}
			}

			// 需要新增的：新列表中有但当前不存在的
			for _, menuId := range req.MenuIds {
				if _, exists := currentMenuMap[menuId]; !exists {
					toInsert = append(toInsert, menuId)
				}
			}

			// 5. 删除需要移除的关联
			for _, roleMenu := range toDelete {
				err = l.svcCtx.AdminRoleMenuModel.Delete(ctx, session, roleMenu.Id)
				if err != nil {
					return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "删除角色菜单关联失败: %v", err)
				}
			}

			// 6. 添加新的关联
            for _, menuId := range toInsert {
                roleMenu := &model.AdminRoleMenu{
                    Id:     uuid.NewString(),
                    RoleId: req.Id,
                    MenuId: menuId,
                }
                _, err = l.svcCtx.AdminRoleMenuModel.Insert(ctx, session, roleMenu)
                if err != nil {
                    return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "添加角色菜单关联失败: %v", err)
                }
            }
		}

		return nil
	})

	if err != nil {
		return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新角色失败err: %v", err)
	}

	return &types.UpdateRoleResp{
		Success: true,
	}, nil
}
