package cn.qinys.platform.upms.api.service.impl;


import cn.qinys.platform.base.exceptions.BizException;
import cn.qinys.platform.base.utils.BeanExUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import cn.qinys.platform.entity.upms.*;
import cn.qinys.platform.upms.api.mapper.*;
import cn.qinys.platform.upms.api.req.*;
import cn.qinys.platform.upms.api.resp.UserAccountInfoResp;
import cn.qinys.platform.upms.api.resp.UserDetailResp;
import cn.qinys.platform.upms.api.resp.UserPageResp;
import cn.qinys.platform.upms.api.service.ICurrentUserService;
import cn.qinys.platform.upms.api.service.ITenantService;
import cn.qinys.platform.upms.config.mybatisplus.TenantContextHolder;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

/**
 * Tenant 的服务实现类
 *
 * @author tanlie
 * @date 2024-05-21
 */
@Service
@Slf4j
@AllArgsConstructor
public class TenantServiceImpl extends ServiceImpl<UpmsTenantMapper, UpmsTenant> implements ITenantService {

    private final UpmsUserMapper userMapper;
    private final UpmsRoleMapper roleMapper;
    private final UpmsMenuMapper menuMapper;
    private final UpmsMenuPermissionMapper menuPermissionMapper;
    private final UpmsMenuBaseMapper menuBaseMapper;
    private final UpmsMenuPermissionBaseMapper permissionBaseMapper;
    private final UpmsUserRoleMapper userRoleMapper;
    private final PasswordEncoder passwordEncoder;
    private final ICurrentUserService currentUserService;

    @Override
    public Page<UpmsTenant> queryPage(TenantQueryReq query) {
        Page<UpmsTenant> page = new Page<>(query.getCurrent(), query.getSize());
        QueryWrapper<UpmsTenant> wrapper = new QueryWrapper<>();
        wrapper.like(StringUtils.hasLength(query.getUrlPrefix()), "url_prefix", query.getUrlPrefix());
        wrapper.like(StringUtils.hasLength(query.getName()), "name", query.getName());
        wrapper.orderByAsc("id");
        return this.baseMapper.selectPage(page, wrapper);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createTenant(TenantCreateReq req) {
        QueryWrapper<UpmsTenant> wrapper = new QueryWrapper<>();
        wrapper.eq("name", req.getName());
        wrapper.last("LIMIT 1");
        UpmsTenant exist = this.baseMapper.selectOne(wrapper);
        if (exist != null) {
            throw new BizException("租户名称已存在");
        }
        QueryWrapper<UpmsTenant> wrapper1 = new QueryWrapper<>();
        wrapper1.eq("name", req.getName());
        wrapper1.last("LIMIT 1");
        UpmsTenant defaultUser = this.baseMapper.selectOne(wrapper1);
        if (defaultUser != null) {
            throw new BizException("默认用户名已存在");
        }

        UpmsTenant tenant = new UpmsTenant();
        tenant.setName(req.getName());
        tenant.setDefaultUsername(req.getDefaultUsername());
        tenant.setRemark(req.getRemark());
        tenant.setCreateTime(new Date());
        tenant.setUpdateTime(new Date());
        super.save(tenant);
        // 新增角色
        TenantContextHolder.setTenantId(tenant.getId());
        UpmsRole role = new UpmsRole();
        role.setDeletable("0");
        role.setSuperAdmin("1");
        role.setTenantId(tenant.getId());
        role.setRoleEnName("system_admin");
        role.setRoleCnName("系统管理员");
        roleMapper.insert(role);
        // 新增系统用户
        UpmsUser user = new UpmsUser();
        user.setUsername(req.getDefaultUsername());
        user.setSex("3");
        user.setFullName("默认用户");
        user.setTenantId(tenant.getId());
        userMapper.insert(user);
        //新增用户角色
        UpmsUserRole userRole = new UpmsUserRole();
        userRole.setUserId(user.getId());
        userRole.setRoleId(role.getId());
        userRole.setActive("1");
        userRoleMapper.insert(userRole);
        TenantContextHolder.clear();
    }

    @Override
    public void updateTenant(TenantUpdateReq req) {
        UpmsTenant tenant = this.baseMapper.selectById(req.getId());
        if (tenant == null) {
            return;
        }
        QueryWrapper<UpmsTenant> wrapper = new QueryWrapper<>();
        wrapper.eq("name", req.getName());
        wrapper.last("LIMIT 1");
        UpmsTenant exist = this.baseMapper.selectOne(wrapper);
        if (exist != null && !exist.getId().equals(tenant.getId())) {
            throw new BizException("租户名称已存在");
        }
        tenant.setName(req.getName());
        tenant.setRemark(req.getRemark());
        tenant.setUpdateTime(new Date());
        super.updateById(tenant);
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public void removeTenant(List<String> ids) {
        //1、锁定所有后台登录用户
        TenantContextHolder.setTenantId(null);
        ids.forEach(userMapper::deleteByTenantId);
        super.removeByIds(ids);
    }

    @Override
    public void syncToTenant(String tenantId) {
        TenantContextHolder.setTenantId(null);
        QueryWrapper<UpmsMenuBase> baseQueryWrapper = new QueryWrapper<>();
        baseQueryWrapper.ne("id", 1).ne("parent_id", 1);
        List<UpmsMenuBase> baseList = menuBaseMapper.selectList(baseQueryWrapper);
        // 复制到租户
        List<String> paths = new ArrayList<>();
        for (UpmsMenuBase base : baseList) {
            paths.add(base.getPath());
            QueryWrapper<UpmsMenu> wrapper = new QueryWrapper<>();
            wrapper.eq("path", base.getPath());
            wrapper.eq("tenant_id", tenantId);
            wrapper.last("LIMIT 1");
            UpmsMenu exist = menuMapper.selectOne(wrapper);
            if (exist != null) {
                //update逻辑
                Integer id = exist.getId();
                BeanUtils.copyProperties(base, exist);
                exist.setId(id);
                exist.setTenantId(tenantId);
                exist.setParentPath(this.getPathByBaseMenuId(exist.getParentId()));
                menuMapper.updateById(exist);
                continue;
            }
            UpmsMenu menu = new UpmsMenu();
            BeanUtils.copyProperties(base, menu);
            menu.setId(null);
            menu.setTenantId(tenantId);
            menu.setParentPath(this.getPathByBaseMenuId(menu.getParentId()));
            menuMapper.insert(menu);
        }
        //删除不在paths 里面的旧数据
        QueryWrapper<UpmsMenu> deleteQuery = new QueryWrapper<>();
        deleteQuery.notIn("path", paths);
        deleteQuery.eq("tenant_id", tenantId);
        menuMapper.delete(deleteQuery);

        // 更新parentId
        QueryWrapper<UpmsMenu> wrapper = new QueryWrapper<>();
        wrapper.eq("tenant_id", tenantId);
        wrapper.ne("parent_id", 0);
        wrapper.orderByAsc("id");
        List<UpmsMenu> childMenus = menuMapper.selectList(wrapper);
        for (UpmsMenu childMenu : childMenus) {
            QueryWrapper<UpmsMenu> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("path", childMenu.getParentPath());
            queryWrapper.eq("tenant_id", tenantId);
            queryWrapper.last("LIMIT 1");
            UpmsMenu parent = menuMapper.selectOne(queryWrapper);
            childMenu.setParentId(parent.getId());
            menuMapper.updateById(childMenu);
        }
        //复制权限码
        this.syncPermissionCodes(tenantId);
        TenantContextHolder.clear();
    }


    @Override
    public Page<UserPageResp> getUserPage(UserPageReq req) {
        Page<UpmsUser> page = new Page<>(req.getCurrent(), req.getSize());
        QueryWrapper<UpmsUser> wrapper = new QueryWrapper<>();
        wrapper.eq("u.deleted", "0");
        wrapper.like(StringUtils.hasLength(req.getFullName()), "u.full_name", req.getFullName());
        wrapper.like(StringUtils.hasLength(req.getMobile()), "u.mobile", req.getMobile());
        wrapper.like(StringUtils.hasLength(req.getTenantName()), "t.name", req.getTenantName());
        wrapper.orderByAsc("u.tenant_id");
        return userMapper.selectUserPage(page, wrapper);
    }

    @Override
    public UserAccountInfoResp getAccountInfo(String id) {
        UpmsUser user = userMapper.selectById(id);
        UserAccountInfoResp resp = new UserAccountInfoResp();
        BeanUtils.copyProperties(user, resp);
        resp.setRoleIds(userRoleMapper.selectRoleIds(id));
        resp.setRoles(roleMapper.selectByTenantId(user.getTenantId()));
        return resp;
    }

    @Override
    public void changeLock(UserChangeLockReq req) {
        List<String> status = Arrays.asList("1", "0");
        if (!status.contains(req.getLocked())) {
            throw new BizException("锁定状态不正确");
        }
        userMapper.updateLockStatus(req.getId(), req.getLocked());
    }

    @Override
    public void resetPassword(UserResetPasswordReq req) {
        String encodePassword = passwordEncoder.encode(req.getPassword());
        UpdateWrapper<UpmsUser> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("id", req.getId());
        UpmsUser entity = new UpmsUser();
        entity.setPassword(encodePassword);
        entity.setExpired("0");
        entity.setPwdExpired(LocalDateTime.now().plusMonths(3));
        entity.setPwdChangeTime(LocalDateTime.now());
        userMapper.update(entity, updateWrapper);
    }

    @Override
    public void userRoleAdd(UserRoleOperationReq req) {
        for (String roleId : req.getRoleIds()) {
            QueryWrapper<UpmsUserRole> wrapper = new QueryWrapper<>();
            wrapper.eq("user_id", req.getId());
            wrapper.eq("role_id", roleId);
            wrapper.last("LIMIT 1");
            UpmsUserRole exist = userRoleMapper.selectOne(wrapper);
            if (exist != null) {
                continue;
            }
            UpmsUserRole role = new UpmsUserRole();
            role.setUserId(req.getId());
            role.setRoleId(roleId);
            userRoleMapper.insert(role);
        }
        currentUserService.refreshUserInfo(req.getId());
    }

    @Override
    public void userRoleDelete(UserRoleOperationReq req) {
        for (String roleId : req.getRoleIds()) {
            // 不能删最后一个
            List<String> roleIds = userRoleMapper.selectRoleIds(req.getId());
            if (roleIds == null || roleIds.size() <= 1) {
                throw new BizException("用户至少要要有一个角色");
            }
            QueryWrapper<UpmsUserRole> wrapper = new QueryWrapper<>();
            wrapper.eq("user_id", req.getId());
            wrapper.eq("role_id", roleId);
            userRoleMapper.delete(wrapper);
        }
        currentUserService.refreshUserInfo(req.getId());
    }

    @Override
    public void removeUser(UserRemoveReq req) {
        userMapper.deleteBatchIds(req.getIds());
    }

    @Override
    public UserDetailResp userDetailById(String userId) {
        UpmsUser user = userMapper.selectById(userId);
        UserDetailResp resp = new UserDetailResp();
        BeanUtils.copyProperties(user, resp);
        return resp;
    }

    @Override
    public void updateUser(UserUpdateReq req) {
        UpdateWrapper<UpmsUser> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("id", req.getId());
        UpmsUser entity = new UpmsUser();
        entity.setAvatar(req.getAvatar());
        BeanUtils.copyProperties(req, entity);
        entity.setUpdateTime(LocalDateTime.now());
        userMapper.update(entity, updateWrapper);
    }

    @Override
    public void createUser(UserCreateReq req) {
        // 账号校验
        UpmsUser exist = userMapper.selectByUsername(req.getUsername());
        if (exist != null) {
            throw new BizException("用户名已存在");
        }
        UpmsUser user = BeanExUtils.convert(req, UpmsUser.class);
        user.setCreateTime(LocalDateTime.now());
        user.setUpdateTime(LocalDateTime.now());
        userMapper.insert(user);
        for (String roleId : req.getRoleIds()) {
            UpmsUserRole role = new UpmsUserRole();
            role.setUserId(user.getId());
            role.setRoleId(roleId);
            userRoleMapper.insert(role);
        }
    }

    private void syncPermissionCodes(String tenantId) {
        QueryWrapper<UpmsMenuPermissionBase> baseQueryWrapper = new QueryWrapper<>();
        baseQueryWrapper.ne("permission_code","upms.menu");
        baseQueryWrapper.orderByAsc("id");
        List<UpmsMenuPermissionBase> baseList = permissionBaseMapper.selectList(baseQueryWrapper);
        List<String> codes = new ArrayList<>();
        for (UpmsMenuPermissionBase base : baseList) {
            codes.add(base.getPermissionCode());
            QueryWrapper<UpmsMenuPermission> wrapper = new QueryWrapper<>();
            wrapper.eq("permission_code", base.getPermissionCode());
            wrapper.eq("tenant_id", tenantId);
            wrapper.last("LIMIT 1");
            UpmsMenuPermission exist = menuPermissionMapper.selectOne(wrapper);
            if (exist != null) {
                exist.setPermissionName(base.getPermissionName());
                exist.setMenuPath(this.getPathByBaseMenuId(base.getMenuId()));
                menuPermissionMapper.updateById(exist);
                continue;
            }
            UpmsMenuPermission permission = new UpmsMenuPermission();
            permission.setMenuId(base.getMenuId());
            permission.setPermissionName(base.getPermissionName());
            permission.setPermissionCode(base.getPermissionCode());
            permission.setTenantId(tenantId);
            permission.setMenuPath(this.getPathByBaseMenuId(base.getMenuId()));
            menuPermissionMapper.insert(permission);
        }
        //删除不在 codes里面的旧数据
        QueryWrapper<UpmsMenuPermission> deleteQuery = new QueryWrapper<>();
        deleteQuery.notIn("permission_code", codes);
        deleteQuery.eq("tenant_id", tenantId);
        menuPermissionMapper.delete(deleteQuery);
        // 更新菜单id
        QueryWrapper<UpmsMenuPermission> wrapper = new QueryWrapper<>();
        wrapper.eq("tenant_id", tenantId);
        List<UpmsMenuPermission> permissionList = menuPermissionMapper.selectList(wrapper);
        for (UpmsMenuPermission permission : permissionList) {
            //获取path 对应的菜单
            QueryWrapper<UpmsMenu> wrapper1 = new QueryWrapper<>();
            wrapper1.eq("path", permission.getMenuPath());
            wrapper1.eq("tenant_id", tenantId);
            wrapper1.last("LIMIT 1");
            UpmsMenu menu = menuMapper.selectOne(wrapper1);
            if (menu != null) {
                permission.setMenuId(menu.getId());
                menuPermissionMapper.updateById(permission);
            }
        }
    }


    private String getPathByBaseMenuId(Integer parentId) {
        UpmsMenuBase base = menuBaseMapper.selectById(parentId);
        return base == null ? null : base.getPath();
    }

}