package com.sdtool.business.service;

import com.sdtool.common.api.*;
import com.sdtool.common.base.BaseService;
import com.sdtool.common.datas.ERPModule;
import com.sdtool.common.datas.HttpCode;
import com.sdtool.common.datas.RedisKeys;
import com.sdtool.common.entity.base.BaseEntity;
import com.sdtool.common.entity.base.DataBaseMultiItemEx;
import com.sdtool.common.entity.base.ProcessEntityItem;
import com.sdtool.common.entity.site.ERPTokenUser;
import com.sdtool.common.entity.site.LoginRequest;
import com.sdtool.common.entity.site.LoginResult;
import com.sdtool.common.entity.system.LoginUser;
import com.sdtool.common.entity.system.Menu;
import com.sdtool.common.entity.system.UserRole;
import com.sdtool.common.tool.TreeMenuUtils;
import com.dySweetFishPlugin.redis.RedisService;
import com.dySweetFishPlugin.sql.RMapUtils;
import com.sweetfish.convert.json.JsonConvert;
import com.sweetfish.service.Local;
import com.sweetfish.service.RetResult;
import com.sweetfish.util.AnyValue;
import com.sweetfish.util.AutoLoad;
import com.sweetfish.util.ResourceType;
import org.apache.commons.lang3.StringUtils;
import org.rex.RMap;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

@AutoLoad(false)
@Local
@ResourceType(LoginService.class)
public class LoginServiceImpl extends BaseService implements LoginService {

    @Resource
    ERPService erpService;

    @Resource
    RedisService redisService;

    @Resource
    NoSqlKeysService keysService;

    @Resource
    SysMessageService sysMessageService;

    @Resource
    JsonConvert jsonConvert;

    @Resource
    DeptService deptService;

    @Resource
    LoginUserService userService;

    @Resource
    RoleService roleService;

    @Override
    public void init(AnyValue config) {
        super.init(config);
    }

    @Override
    public void destroy(AnyValue config) {
        super.destroy(config);
    }

    /**
     * 把平表结构的菜单变成树形菜单
     *
     * @param menuList 菜单平表
     * @return 树形菜单
     */
    private List<Menu> processTreeMenus(List<Menu> menuList) {
        //排序完成后进行树形处理
        return TreeMenuUtils.generateTreeMenus(menuList, 0);
    }

    /**
     * 处理角色对应的菜单为树形结构
     *
     * @param roleList 角色列表
     * @return 角色菜单
     */
    private List<Menu> processUserRoleMenus(List<UserRole> roleList, long supplierCode) {
        List<Menu> result = new ArrayList<>();

        for (UserRole userRole : roleList) {
            Map<String, String> redisMap = redisService.hgetAll(keysService.getRedisKey(RedisKeys.KEY_SYSROLEMENUS, supplierCode, true) + userRole.getRoleId());
            String[] resourceIds = redisMap.keySet().toArray(new String[0]);

            if (resourceIds.length > 0) {
                List<String> menuRedisList = redisService.hmget(keysService.getRedisKey(RedisKeys.KEY_SYSMENUS, supplierCode), resourceIds);

                for (String menuStr : menuRedisList) {
                    if (StringUtils.isNotEmpty(menuStr)) {
                        Menu menu = jsonConvert.convertFrom(Menu.class, menuStr);
                        result.add(menu);
                    }
                }
            }
        }

        //去重
        result = result.stream().filter(Objects::nonNull).distinct().collect(Collectors.toList());
        //排序
        result.sort((v1, v2) -> {
            if (v1.getParentId() == v2.getParentId()) {
                return Integer.compare(v1.getSortNum(), v2.getSortNum());
            } else {
                return Long.compare(v1.getParentId(), v2.getParentId());
            }
        });

        return processTreeMenus(result);
    }

    private List<Menu> getCurrentUserMenus(LoginUser user, String dataSourceId, long supplierCode) {

        List<UserRole> userRoleList = roleService.getUserRoleList(user.getId(), dataSourceId, supplierCode);
        user.setRoleList(userRoleList);

        return processUserRoleMenus(user.getRoleList(), supplierCode);
    }

    /**
     * 登录
     *
     * @param bean 登录信息
     * @return 登录信息
     */
    public RetResult<LoginResult> login(LoginRequest bean, String clientIp) {
        DataBaseMultiItemEx supplierItem;

        if ((bean.getSupplierId() <= 0L) && (bean.getSupplierCode() <= 0L)) {
            return RetResult.<LoginResult>errorT().retinfo("请选择登录公司信息");
        }

        if (bean.getSupplierId() <= 0L) {
            supplierItem = erpService.getERPSupplierInfoBySharding(bean.getSupplierCode());
        } else {
            supplierItem = erpService.getERPSupplierInfo(bean.getSupplierId());
        }

        if (supplierItem == null) {
            return RetResult.<LoginResult>errorT().retinfo("无效的登录公司信息");
        }

        bean.setSupplierId(supplierItem.getId());
        bean.setSupplierCode(Long.parseLong(supplierItem.getShardingKey()));
        bean.setClientIp(clientIp);

        return handleScript("ERPLogin",
                ERPModule.LOGIN,
                supplierItem.getDataBaseAlias(),
                Long.parseLong(supplierItem.getShardingKey()),
                () -> ProcessEntityItem.<LoginRequest>newBuilder()
                        .inputItem(bean)
                        .currentUser(null)
                        .dataSourceId(supplierItem.getDataBaseAlias())
                        .supplierCode(Long.parseLong(supplierItem.getShardingKey()))
                        .build()
        );
    }

    public RetResult<BaseEntity> checkUser(ERPTokenUser tokenUser) {
        return handleScript("ERPLoginCheck",
                ERPModule.LOGIN,
                tokenUser.getDataSourceId(),
                tokenUser.getSupplierCode(),
                () -> ProcessEntityItem.<BaseEntity>newBuilder()
                        .inputItem(null)
                        .currentUser(tokenUser)
                        .dataSourceId(tokenUser.getDataSourceId())
                        .supplierCode(tokenUser.getSupplierCode())
                        .build()
        );
    }

    /**
     * 当前用户获取首页基础内容
     * 包括 用户信息，菜单信息，一些基本的配置信息
     *
     * @param currentUser  当前用户
     * @param dataSourceId 分库
     * @param supplierCode 分表
     * @return 用户信息，菜单信息
     */
    @SuppressWarnings({"unchecked", "rawtypes"})
    public RMap getIndexContent(ERPTokenUser currentUser, String dataSourceId, long supplierCode) {
        if (currentUser == null) {
            return RMapUtils.error(HttpCode.UNAUTHORIZED.value(), "未登录");
        }

        //2021-01-26 改为从redis中获取，避免查询数据库
        LoginUser userInfo = userService.getRedisLoginUser(currentUser.getId(), supplierCode);
        if (userInfo == null) {
            return RMapUtils.error(HttpCode.UNAUTHORIZED.value(), "未登录");
        }

        RMap content = new RMap();
        userInfo.setPassword("");
        userInfo.setSalt("");
        if (userInfo.getId() != 0L) {
            userInfo.setDeptName(deptService.getRedisDeptName(userInfo.getDeptId(), supplierCode));
        } else {
            userInfo.setDeptName("菜单管理");
        }

        if (StringUtils.isEmpty(userInfo.getAvatar())) {
            userInfo.setAvatar("/img/profile.png");
        } else {
            userInfo.setAvatar("/apis/avatar/" + supplierCode + "/" + userInfo.getAvatar());
        }

        content.put("user", userInfo);
        //增加supplierCode，后续websocket登录需要
        content.put("supplierCode", supplierCode);
        content.put("dataSourceId", dataSourceId);
        //增加当前分厂名称
        //2022-07-14暂时改为服务获取，不通过http，防止连接数过多
        //正常处理应该单独给中心服务启动一个进程，本地需要做缓存，或启动时获取一次，然后每隔多少时间刷新即可，减少客户网页刷新带来的连接数增多的情况
        DataBaseMultiItemEx supplierInfo = erpService.getERPSupplierInfoBySharding(supplierCode);
        if (supplierInfo != null) {
            content.set("supplierName", supplierInfo.getItemName());
        }

        content.put("menus", getCurrentUserMenus(userInfo, dataSourceId, supplierCode));

        //获取未读消息数量
        content.put("messageCount", sysMessageService.queryUnReadMessageCount(userInfo.getId(), supplierCode));

        content.put("copyrightYear", "todo");

        return RMapUtils.successV2(content, null, null);
    }
}
