package com.bocloud.ims.service.upgrade.migration.from50to55;

import com.bocloud.ims.service.upgrade.AbstractUpgradeTask;
import com.bocloud.ims.service.upgrade.UpgradeVersion;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.stereotype.Component;

import java.util.*;

/**
 * permission数据导入任务
 * 1. 不考虑客户环境相对于5.0增减菜单的情况，极少，忽略
 * 2. 无法考虑客户更改了菜单名称、排序等情况，因为升级过程只能提供客户数据库和5.5标准库
 *    而客户自己更改了菜单名称、排序等情况只能通过客户数据库和5.0标准库比对才能知晓
 * 基于以上两点，permission表维持5.5的数据不变即可
 *
 * 但是，5.5需要将permission表的id重新整理排序，排序时要同步处理role_permission表
 * @author luyanchao
 * @date 2021-06-09
 */
@Component("5.0-5.5-PermissionTask")
public class PermissionTask extends AbstractUpgradeTask {

    private final ApplicationContext context;

    @Autowired
    public PermissionTask(ApplicationContext context) {
        this.context = context;
    }

    @Override
    public UpgradeVersion getUpgradeVersion() {
        return UpgradeVersion.from50to55;
    }

    /**
     * 到数据库按parentId查询权限
     * @param parentId 父id
     * @return 子权限列表
     */
    private List<Map<String, Object>> getPermissionByParentId(Long parentId) {
        NamedParameterJdbcTemplate jdbcTemplate = context.getBean(NamedParameterJdbcTemplate.class);
        String sql = "select id, name, priority from permission where parent_id = :parentId ";
        Map<String, Object> params = Collections.singletonMap("parentId", parentId);
        return jdbcTemplate.queryForList(sql, params);
    }

    /**
     * 递归构建权限的属性结构数据
     * @param permission 权限
     */
    private void getPermissionTree(Map<String, Object> permission) {
        long permissionId = Long.parseLong(permission.get("id").toString());
        List<Map<String, Object>> children = this.getPermissionByParentId(permissionId);
        children.forEach(this::getPermissionTree);
        permission.put("children", children);
    }

    @Override
    @SuppressWarnings("unchecked")
    public void run() {
        final long increment = 10000000000L;
        NamedParameterJdbcTemplate jdbcTemplate = context.getBean(NamedParameterJdbcTemplate.class);
        // 查询permission，构建tree数据结构
        List<Map<String, Object>> rootPermissions = this.getPermissionByParentId(0L);
        rootPermissions.forEach(this::getPermissionTree);
        // 将permissionId增加10000000000，避免后面更新id的时候发生主键冲突的问题
        Map<String, Long> incrementMap = Collections.singletonMap("increment", increment);
        jdbcTemplate.update("update permission set id = id + :increment where 1=1 ", incrementMap);
        jdbcTemplate.update("update permission set parent_id = parent_id + :increment where parent_id != 0 ", incrementMap);
        jdbcTemplate.update("update role_permission set permission_id = permission_id + :increment where 1=1 ", incrementMap);
        // 逐层生成新的id并更新
        int index = 1;
        List<Map<String, Object>> currPermissions = new ArrayList<>(rootPermissions);
        while (currPermissions.size() > 0) {
            List<Map<String, Object>> childPermissions = new ArrayList<>();
            for (Map<String, Object> currPermission : currPermissions) {
                long currPermissionId = Long.parseLong(currPermission.get("id").toString());
                Map<String, Object> sqlParams = new HashMap<>();
                sqlParams.put("index", index);
                sqlParams.put("id", currPermissionId + increment);
                jdbcTemplate.update("update permission set id = :index where id = :id ", sqlParams);
                jdbcTemplate.update("update permission set parent_id = :index where parent_id = :id ", sqlParams);
                jdbcTemplate.update("update role_permission set permission_id = :index where permission_id = :id ", sqlParams);
                if (currPermission.containsKey("children")) {
                    childPermissions.addAll((List<Map<String, Object>>) currPermission.get("children"));
                }
                index++;
            }
            currPermissions = childPermissions;
        }
    }
}
