package com.tuoheng.service.impl;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.tuoheng.common.ServiceException;
import com.tuoheng.constant.HhzUrlConstant;
import com.tuoheng.mapper.*;
import com.tuoheng.model.dto.*;
import com.tuoheng.model.param.*;
import com.tuoheng.model.po.AuthoritiesPo;
import com.tuoheng.model.po.ClientUserRolePo;
import com.tuoheng.model.po.TenantPo;
import com.tuoheng.model.po.UserPo;
import com.tuoheng.model.query.TenantQuery;
import com.tuoheng.model.vo.BusinessSystemVo;
import com.tuoheng.model.vo.TenantVo;
import com.tuoheng.service.ClientUserSevice;
import com.tuoheng.until.JsonResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.*;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author chenjiandong
 * @description: TODO
 * @date 2022/10/8 11:35
 */
@Service
@Slf4j
public class ClientUserServiceImpl implements ClientUserSevice {

    @Autowired
    private ClientUserMapper clientUserMapper;

    @Autowired
    private TenantMapper tenantMapper;

    @Autowired
    private AuthoritiesMapper authoritiesMapper;

    @Autowired
    private ClientUserRoleMapper clientUserRoleMapper;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private PlatformMapper platformMapper;
    @Autowired
    private Oauth2RegisteredClientMapper oauth2RegisteredClientMapper;

    @Override
    @Transactional(readOnly = true)
    public JsonResult judgeCreate(String username) {
        if (clientUserMapper.judgeCreateByUserName(username) > 0) {
            return JsonResult.success(false);
        }
        return JsonResult.success(true);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public JsonResult createClientUser(CreateClientUserDto createClientUserDto, LoginUser loginUser) {

        if (clientUserMapper.judgeCreateByUserName(createClientUserDto.getUsername()) > 0) {
            return JsonResult.error("该用户名称已存在！");
        }

        UserPo userPo = new UserPo()
                .setUsername(createClientUserDto.getUsername())
                .setPassword("{bcrypt}" + new BCryptPasswordEncoder().encode(createClientUserDto.getPassword()));
        userPo.setCreateUser(loginUser.getUserId());
        //租户逻辑新增 start
        if (createClientUserDto.getTenantFlag() != null) {
            if (createClientUserDto.getTenantFlag() == 1) {
                userPo.setIsTenant(1);
            } else {
                userPo.setIsTenant(0);
                UserPo po = clientUserMapper.getUserByUserName(createClientUserDto.getTenantName());
                if (po != null) {
                    userPo.setTenantId(po.getId());
                }
            }
        }
        //租户逻辑新增 end
        clientUserMapper.insertClientUser(userPo);
        if (createClientUserDto.getTenantFlag() != null) {
            if (createClientUserDto.getTenantFlag() == 1) {
                TenantPo tenantPo = new TenantPo();
                tenantPo.setUserId(userPo.getId());
                //添加租户code
                tenantPo.setCode(createClientUserDto.getCode());
                tenantPo.setName(createClientUserDto.getName());
                tenantMapper.insertTenant(tenantPo);
            }
        }
        List<AuthoritiesPo> authoritiesPos = new ArrayList<>();
        List<ClientUserRolePo> clientUserRolePoArrayList = new ArrayList<>();
        for (ClientRoleDto clientRoleDto : createClientUserDto.getClientRoleDtoList()) {
            AuthoritiesPo authoritiesPo = new AuthoritiesPo()
                    .setUserId(userPo.getId())
                    .setUsername(createClientUserDto.getUsername())
                    .setAuthority(clientRoleDto.getClientId());
            authoritiesPo.setCreateUser(loginUser.getUserId());
            authoritiesPos.add(authoritiesPo);

            ClientUserRolePo clientUserRolePo = new ClientUserRolePo()
                    .setUserId(userPo.getId())
                    .setClientId(clientRoleDto.getClientId())
                    .setRoleId(clientRoleDto.getRoleId());
            clientUserRolePo.setCreateUser(loginUser.getUserId());
            clientUserRolePoArrayList.add(clientUserRolePo);

        }
        authoritiesMapper.batchInsert(authoritiesPos);
        clientUserRoleMapper.batchInsert(clientUserRolePoArrayList);
        return JsonResult.success(userPo.getId());
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public JsonResult createClientTenant(CreateClientTenantDto createClientTenantDto, LoginUser loginUser) {

        if (clientUserMapper.judgeCreateByUserName(createClientTenantDto.getUsername()) > 0) {
            return JsonResult.error("该用户名称已存在！");
        }
        UserPo userPo = new UserPo()
                .setIsTenant(1)
                .setUsername(createClientTenantDto.getUsername())
                .setPassword("{bcrypt}" + new BCryptPasswordEncoder().encode(createClientTenantDto.getPassword()));
        userPo.setCreateUser(loginUser.getUserId());
        clientUserMapper.insertClientUser(userPo);
        TenantPo tenantPo = new TenantPo()
                .setUserId(userPo.getId())
                .setRemark(createClientTenantDto.getRemark());
        tenantMapper.insertTenant(tenantPo);
        List<AuthoritiesPo> authoritiesPos = new ArrayList<>();
        List<ClientUserRolePo> clientUserRolePoArrayList = new ArrayList<>();
        for (ClientRoleDto clientRoleDto : createClientTenantDto.getClientRoleDtoList()) {
            AuthoritiesPo authoritiesPo = new AuthoritiesPo()
                    .setUserId(userPo.getId())
                    .setUsername(createClientTenantDto.getUsername())
                    .setAuthority(clientRoleDto.getClientId());
            authoritiesPo.setCreateUser(loginUser.getUserId());
            authoritiesPos.add(authoritiesPo);

            ClientUserRolePo clientUserRolePo = new ClientUserRolePo()
                    .setUserId(userPo.getId())
                    .setClientId(clientRoleDto.getClientId())
                    .setRoleId(clientRoleDto.getRoleId());
            clientUserRolePo.setCreateUser(loginUser.getUserId());
            clientUserRolePoArrayList.add(clientUserRolePo);

        }
        authoritiesMapper.batchInsert(authoritiesPos);
        clientUserRoleMapper.batchInsert(clientUserRolePoArrayList);
        //todo:调用业务系统完成租户创建
        return JsonResult.success(userPo.getId());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public JsonResult updateUserPassword(UpdateUserPassDto updateUserPassDto, LoginUser loginUser) {

        if (clientUserMapper.getUserByUserName(updateUserPassDto.getUsername()) == null) {
            return JsonResult.error("该用户不存在！");
        }
        UserPo userPo = new UserPo()
                .setUsername(updateUserPassDto.getUsername())
                .setPassword("{bcrypt}" + new BCryptPasswordEncoder().encode(updateUserPassDto.getPassword()));
        userPo.setUpdateUser(loginUser.getUserId());
        clientUserMapper.updatePass(userPo);
        return JsonResult.success(true);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public JsonResult updateUserClientRole(UpdateUserClientRoleDto updateUserClientRoleDto, LoginUser loginUser) {
        UserPo userPo = clientUserMapper.getUserByUserName(updateUserClientRoleDto.getUsername());
        if (userPo == null) {
            return JsonResult.error("该用户不存在！");
        }
        List<ClientRoleDto> clientRoleDtoList = updateUserClientRoleDto.getClientRoleDtoList();
        for (ClientRoleDto dto : clientRoleDtoList) {
            ClientUserRolePo clientUserRolePo = new ClientUserRolePo()
                    .setUserId(userPo.getId())
                    .setClientId(dto.getClientId())
                    .setRoleId(dto.getRoleId());
            clientUserRolePo.setUpdateUser(loginUser.getUserId());
            if (clientUserRoleMapper.updateUserClientRole(clientUserRolePo) == 0) {
                ClientUserRolePo insert = new ClientUserRolePo();
                insert.setUserId(userPo.getId())
                        .setClientId(dto.getClientId())
                        .setRoleId(dto.getRoleId())
                        .setCreateUser(loginUser.getUserId());
                clientUserRoleMapper.insert(insert);
            }
        }
        return JsonResult.success(true);
    }

    /**
     * 新增业务平台的租户基本数据
     *
     * @param dto
     * @return
     */
    @Override
    @Transactional
    public JsonResult addTenant(OidcTenantDto dto, LoginUser loginUser) {

        if (clientUserMapper.judgeCreateByUserName(dto.getUsername()) > 0) {
            return JsonResult.error("该用户名称已存在！");
        }

        if (ObjectUtil.isEmpty(dto.getCode())) {
            return JsonResult.error("租户code不能为空");
        }
        TTenant tTenant = tenantMapper.getByCode(dto.getCode());
        if (ObjectUtil.isNotNull(tTenant)) {
            return JsonResult.error("该租户code已存在,请重新输入");
        }
        if (dto.getClientId().contains(",")) {
            String[] codes = dto.getClientId().split(",");
            for (String code : codes) {
                return getResult(dto, code, loginUser);
            }
        } else {
            return getResult(dto, dto.getClientId(), loginUser);
        }
        return JsonResult.success();
    }

    /**
     * 查询租户以及该租户对应绑定的系统等
     *
     * @return
     */
    @Override
    public JsonResult findTenants(TenantQuery query) {
        if (ObjectUtil.isNull(query.getPage()) || ObjectUtil.isNull(query.getLimit())) {
            return JsonResult.error("分页参数不能为空");
        }
        //开启分页
        IPage<TenantVo> page = new Page<>(query.getPage(), query.getLimit());
        IPage<TenantPo> pageData = tenantMapper.findList(page, query);
        pageData.convert(x -> {
            TenantVo vo = Convert.convert(TenantVo.class, x);
            if (ObjectUtil.isNotEmpty(vo.getCode())) {
            }
            Long userId = x.getUserId();
            List<AuthoritiesPo> poList = authoritiesMapper.selectByUserId(userId);
            UserPo userPo = clientUserMapper.selectByUserId(userId);
            if (null != userPo) {
                vo.setUsername(userPo.getUsername());
            }
            List<BusinessSystemVo> businessSystemVoList = new ArrayList<>();
            for (AuthoritiesPo authoritiesPo : poList) {
                BusinessSystemVo businessSystemVo = new BusinessSystemVo();
                //TODO 后期维护各个业务平台
                if (authoritiesPo.getAuthority().contains("hhz")) {
                    businessSystemVo.setClientId(HhzUrlConstant.HHZ_CLIENT);
                    businessSystemVo.setName(HhzUrlConstant.HHZ_NAME);
                    businessSystemVoList.add(businessSystemVo);
                }
            }
            businessSystemVoList = businessSystemVoList.stream().distinct().collect(Collectors.toList());
            vo.setList(businessSystemVoList);
            return vo;
        });
        //过滤出测试租户数据
        List<TenantPo> collect = pageData.getRecords().stream().filter(t -> ObjectUtil.isNotEmpty(t.getCode())).collect(Collectors.toList());
        pageData.setRecords(collect);
        return JsonResult.success(pageData);
    }

    /**
     * 删除租户(逻辑删除)
     *
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public JsonResult deleteTenant(OidcTenantDto dto, LoginUser loginUser) {
        TenantPo tenantPo = tenantMapper.selectById(dto.getId());
        tenantPo.setEnabled(0);
        tenantMapper.updateById(tenantPo);
        UserPo userPo = clientUserMapper.selectByUserId(tenantPo.getUserId());
        userPo.setEnabled(0);
        clientUserMapper.updatePass(userPo);
        if (dto.getClientId().contains(",")) {
            String[] codes = dto.getClientId().split(",");
            for (String code : codes) {
                return deleteResult(dto, code, loginUser);
            }
        } else {
            return deleteResult(dto, dto.getClientId(), loginUser);
        }
        return JsonResult.success();
    }

    /**
     * 更新业务平台租户的相关基本信息
     *
     * @param dto
     * @param loginUser
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public JsonResult editTenant(OidcTenantDto dto, LoginUser loginUser) {

        if (ObjectUtil.isEmpty(dto.getCode())) {
            return JsonResult.error("租户code不能为空");
        }
        if (dto.getClientId().contains(",")) {
            String[] codes = dto.getClientId().split(",");
            for (String code : codes) {
                JsonResult jsonResult = editResult(dto, code, loginUser);
                if (!"操作成功".equals(jsonResult.getMsg())) {
                    return jsonResult;
                }
            }
        } else {
            JsonResult jsonResult = editResult(dto, dto.getClientId(), loginUser);
            if (!"操作成功".equals(jsonResult.getMsg())) {
                return jsonResult;
            }
        }
        TTenant tTenant = tenantMapper.getByCode(dto.getCode());
        dto.setId(tTenant.getId());

        TenantPo tenantPo = new TenantPo();
        tenantPo.setName(dto.getName())
                .setId(dto.getId());
        tenantMapper.updateById(tenantPo);
        //更新密码
        if (ObjectUtil.isNotEmpty(dto.getPassword())) {
            UserPo userPo = new UserPo();
            userPo.setUsername(dto.getUsername());
            dto.setPassword("{bcrypt}" + new BCryptPasswordEncoder().encode(dto.getPassword()));
            userPo.setPassword(dto.getPassword());
            clientUserMapper.updatePass(userPo);
        }
        return JsonResult.success();
    }

    /**
     * 新增请求
     *
     * @param dto
     * @param code
     * @param loginUser
     * @return
     */
    private JsonResult getResult(OidcTenantDto dto, String code, LoginUser loginUser) {
        Platform platform = platformMapper.selectOne(Wrappers.<Platform>lambdaQuery()
                .eq(Platform::getPlatformCode, code)
                .eq(Platform::getMark, 1));
        if (ObjectUtil.isNull(platform)) {
            return JsonResult.error("该业务平台不存在");
        }
        //设置请求头
        HttpHeaders resultRequestHeader = new HttpHeaders();
        resultRequestHeader.add("Authorization", "Bearer " + loginUser.getThToken());
        HttpEntity httpEntity = new HttpEntity(dto, resultRequestHeader);
        //设置地址(hhz平台)
        String url = platform.getPlatformUrl();
        //根据不同业务平台进行动态匹配
        //TODO 后期维护各个业务平台
        if (url.contains("hhz")) {
            url = url + HhzUrlConstant.CREATE_TENANT;
        }
        ResponseEntity<JsonResult> response;
        try {
            response = restTemplate.exchange(url, HttpMethod.POST, httpEntity, JsonResult.class);
        } catch (Exception e) {
            throw new ServiceException(HttpStatus.BAD_REQUEST.value(), "业务平台新增租户失败");
        }
        if (null == response || !response.hasBody()) {
            log.error("业务平台新增租户响应失败");
            throw new ServiceException(HttpStatus.BAD_REQUEST.value(), "业务平台新增租户失败");
        }
        if (response.getBody().getCode() != JsonResult.SUCCESS) {
            log.error("业务平台新增租户响应失败" + response.getBody());
            return JsonResult.error(response.getBody().getMsg());
        }
        return JsonResult.success();
    }

    /**
     * 更新请求
     *
     * @param dto
     * @param code
     * @param loginUser
     * @return
     */
    private JsonResult editResult(OidcTenantDto dto, String code, LoginUser loginUser) {
        Platform platform = platformMapper.selectOne(Wrappers.<Platform>lambdaQuery()
                .eq(Platform::getPlatformCode, code)
                .eq(Platform::getMark, 1));
        if (ObjectUtil.isNull(platform)) {
            return JsonResult.error("该业务平台不存在");
        }
        //设置请求头
        HttpHeaders resultRequestHeader = new HttpHeaders();
        resultRequestHeader.add("Authorization", "Bearer " + loginUser.getThToken());
        HttpEntity httpEntity = new HttpEntity(dto, resultRequestHeader);
        //设置地址(hhz平台)
        String url = platform.getPlatformUrl();
        //根据不同业务平台进行动态匹配
        if (url.contains("hhz")) {
            url = url + HhzUrlConstant.UPDATE_TENANT;
        }
        //else if (url.contains("lc")) {
        //    url = url + HhzUrlConstant.UPDATE_TENANT;
        //} else if (url.contains("gs")) {
        //    url = url + HhzUrlConstant.UPDATE_TENANT;
        //}
        ResponseEntity<JsonResult> response;
        try {
            response = restTemplate.exchange(url, HttpMethod.POST, httpEntity, JsonResult.class);
        } catch (Exception e) {
            throw new ServiceException(HttpStatus.BAD_REQUEST.value(), "业务平台更新租户失败");
        }
        if (null == response || !response.hasBody()) {
            log.error("业务平台更新租户响应失败");
            throw new ServiceException(HttpStatus.BAD_REQUEST.value(), "业务平台更新租户失败");
        }
        if (response.getBody().getCode() != JsonResult.SUCCESS) {
            log.error("业务平台更新租户响应失败" + response.getBody());
            return JsonResult.error(response.getBody().getMsg());
        }
        return JsonResult.success();
    }

    /**
     * 删除请求
     *
     * @param dto
     * @param code
     * @param loginUser
     * @return
     */
    private JsonResult deleteResult(OidcTenantDto dto, String code, LoginUser loginUser) {
        Platform platform = platformMapper.selectOne(Wrappers.<Platform>lambdaQuery()
                .eq(Platform::getPlatformCode, code)
                .eq(Platform::getMark, 1));
        if (ObjectUtil.isNull(platform)) {
            return JsonResult.error("该业务平台不存在");
        }
        //设置请求头
        HttpHeaders resultRequestHeader = new HttpHeaders();
        resultRequestHeader.add("Authorization", "Bearer " + loginUser.getThToken());
        HttpEntity httpEntity = new HttpEntity(dto, resultRequestHeader);
        //设置地址(hhz平台)
        String url = platform.getPlatformUrl();
        //根据不同业务平台进行动态匹配
        if (url.contains("hhz")) {
            url = url + HhzUrlConstant.DELETE_TENANT;
        }
        //else if (url.contains("lc")) {
        //    url = url + HhzUrlConstant.UPDATE_TENANT;
        //} else if (url.contains("gs")) {
        //    url = url + HhzUrlConstant.UPDATE_TENANT;
        //}
        ResponseEntity<JsonResult> response;
        try {
            response = restTemplate.exchange(url, HttpMethod.POST, httpEntity, JsonResult.class);
        } catch (Exception e) {
            throw new ServiceException(HttpStatus.BAD_REQUEST.value(), "业务平台删除租户失败");
        }
        if (null == response || !response.hasBody()) {
            log.error("业务平台删除租户响应失败");
            throw new ServiceException(HttpStatus.BAD_REQUEST.value(), "业务平台删除租户失败");
        }
        if (response.getBody().getCode() != JsonResult.SUCCESS) {
            log.error("业务平台删除租户响应失败" + response.getBody());
            return JsonResult.error(response.getBody().getMsg());
        }
        return JsonResult.success();
    }
}
