package com.testor.module.iam.service.impl;

import cn.hutool.core.lang.UUID;
import com.alibaba.excel.EasyExcel;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.testor.biz.auth.model.TokenResponse;
import com.testor.biz.auth.model.UserInfoResponse;
import com.testor.biz.auth.service.AuthService;
import com.testor.biz.excel.ExcelEnum;
import com.testor.biz.sys.org.model.domain.SysOrg;
import com.testor.biz.sys.org.service.SysOrgService;
import com.testor.biz.sys.user.model.domain.SysUser;
import com.testor.biz.sys.user.model.dto.UserExport;
import com.testor.biz.sys.user.service.SysUserService;
import com.testor.common.constant.IamBindStatusEnum;
import com.testor.common.constant.IamErrorEnum;
import com.testor.common.constant.StatusEnum;
import com.testor.module.iam.dao.IamSysUserDao;
import com.testor.module.iam.model.domain.IamMessage;
import com.testor.module.iam.model.domain.IamSysUser;
import com.testor.module.iam.model.domain.IamUserMapping;
import com.testor.module.iam.model.dto.IamLoginDto;
import com.testor.module.iam.model.dto.IamUserQueryDto;
import com.testor.module.iam.model.dto.IamUserResponse;
import com.testor.module.iam.service.IamDepartmentService;
import com.testor.module.iam.service.IamSysUserService;
import com.testor.module.iam.service.IamUserMappingService;
import com.testor.module.iam.util.RequestIamUtil;
import com.testor.module.sys.model.dto.SysUserListResponse;
import com.testor.module.sys.model.dto.SysUserParam;
import com.tongtech.tfw.backend.common.biz.constants.BizConstants;
import com.tongtech.tfw.backend.common.biz.models.BaseResponse;
import com.tongtech.tfw.backend.common.jwt.JwtHelper;
import com.tongtech.tfw.backend.common.models.exceptions.ApiException;
import com.tongtech.tfw.backend.common.models.supers.SuperServiceImpl;
import com.tongtech.tfw.backend.core.helper.IdHelper;
import com.tongtech.tfw.backend.core.helper.ObjectHelper;
import com.tongtech.tfw.backend.core.helper.StringHelper;
import com.tongtech.tfw.backend.core.helper.bean.BeanHelper;
import com.tongtech.tfw.backend.core.helper.datetime.DatetimeHelper;
import lombok.extern.slf4j.Slf4j;
import org.jose4j.jwt.JwtClaims;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.RequestParam;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @ClassName: IamSysUserServiceImpl
 * @Description: TODO
 * @Author: lm
 * @CreateTime: 2023/12/29 15:08
 * @Version: 1.0
 */
@Service("IamSysUserService")
@Slf4j
public class IamSysUserServiceImpl extends SuperServiceImpl<IamSysUserDao, IamSysUser> implements IamSysUserService {

    @Autowired
    private RequestIamUtil requestIamUtil;
    @Autowired
    private IamUserMappingService iamUserMappingService;
    @Autowired
    private AuthService authService;

    @Autowired
    private SysOrgService sysOrgService;

    @Autowired
    private IamDepartmentService iamDepartmentService;

    @Autowired
    private SysUserService sysUserService;

    @Resource
    private RedisTemplate<String, String> redisTemplate;

    @Override
    public BaseResponse getToken(IamLoginDto iamLoginDto) {
        BaseResponse baseResponse = new BaseResponse();
        //校验key
        Boolean aBoolean = verifyUserKey(iamLoginDto.getUserKeyPid(),iamLoginDto.getUserId());
        if (!aBoolean){
            baseResponse.setCode(IamBindStatusEnum.GET_TOKEN.code());
            baseResponse.setMsg(IamBindStatusEnum.GET_TOKEN.msg());
            return baseResponse;
        }
        IamUserMapping byUserId = iamUserMappingService.getByUserId(iamLoginDto.getUserId());
        String iamUserId = byUserId.getIamUserId();
        List<IamUserMapping> iamUserMapping = iamUserMappingService.getByIamUserId(iamUserId);
        if (!CollectionUtils.isEmpty(iamUserMapping)) {
            // 每次登录更新IAM用户信息
            updateIamUser(iamUserId);
            UserInfoResponse userInfoResponse = authService.getUserInfo(iamLoginDto.getUserId());
            if (userInfoResponse != null && userInfoResponse.getUserInfo() != null) {
                SysUser byId = sysUserService.getById(userInfoResponse.getUserInfo().getUserId());
                String status = byId.getStatus();
                //判断用户是否被禁用
                if (status.equals(StatusEnum.DEACTIVATE.getCode())) {
                    baseResponse.setCode(IamBindStatusEnum.DEACTIVATED.code());
                    baseResponse.setMsg(IamBindStatusEnum.DEACTIVATED.msg());
                    return baseResponse;
                }
            }
            String jwt = JwtHelper.issueJwtAuth0(IdHelper.getId32bit(), iamLoginDto.getUserId(), JSON.toJSONString(userInfoResponse.getUserInfo()), "Token Issuer", "", 36000L);
            TokenResponse build = TokenResponse.builder().token(jwt).expired(36000L).build();
            baseResponse.setData(build);
        } else {
            baseResponse.setCode(IamBindStatusEnum.UNBOUND.code());
            baseResponse.setMsg(IamBindStatusEnum.UNBOUND.msg());
            IamUserResponse iamUserResponse = new IamUserResponse();
            iamUserResponse.setIamUserId(iamUserId);
            baseResponse.setData(iamUserResponse);
        }
        return baseResponse;
    }

    private Boolean verifyUserKey(String userKeyPid,String userId) {
        String value = redisTemplate.opsForValue().get(userKeyPid);
        if (ObjectHelper.isNotEmpty(value)) {
            boolean equals = value.equals(userId);
            //删除key
            redisTemplate.delete(userKeyPid);
            return equals;
        }
        return false;
    }

    @Override
    public boolean handleMessage(IamMessage iamMessage) {
        boolean flag = false;
        switch (iamMessage.getOperateType()) {
            case "DELETE":
                remove((Wrapper) (new QueryWrapper()).eq("user_id", iamMessage.getDataId()));
                iamUserMappingService.deleteByIamUserId(iamMessage.getDataId());
                flag = true;
                break;
            default:
                IamUserQueryDto dto = new IamUserQueryDto();
                dto.setUserid(iamMessage.getDataId());
                List<IamSysUser> list = requestIamUtil.getUser(dto);
                if (!CollectionUtils.isEmpty(list)) {
                    IamSysUser user = list.get(0);
                    user.setUpdateDate(new Date());
                    flag = saveOrUpdate(user);
                }
                break;
        }
        return flag;
    }

    @Override
    public Page<SysUserListResponse> querySysUserList(SysUserParam queryParam) {
        queryParam.setPage(queryParam.getPage() < 1 ? BizConstants.PAGE : queryParam.getPage());
        queryParam.setLimit(queryParam.getLimit() < 1 ? BizConstants.LIMIT : queryParam.getLimit());
        Long page = queryParam.getPage();
        Long limit = queryParam.getLimit();
        Page<SysUserListResponse> resultPage = new Page(page, limit);
        queryParam.setOffset((page - 1) * limit);
        if (!StringHelper.isEmpty(queryParam.getOrgId())) {
            List<String> orgList = (List) this.sysOrgService.getChildrenById(queryParam.getOrgId()).stream().map(SysOrg::getOrgId).collect(Collectors.toList());
            if (!orgList.isEmpty()) {
                orgList.add(queryParam.getOrgId());
                queryParam.setOrgIdList(orgList);
            } else {
                queryParam.setOrgIdList(Arrays.asList(queryParam.getOrgId()));
            }
        }
        if (StringHelper.isEmpty(queryParam.getStatus())) {
            queryParam.setStatusList(Arrays.asList("0", "2"));
        } else if (!"1".equals(queryParam.getStatus())) {
            queryParam.setStatusList(Arrays.asList(queryParam.getStatus()));
        }

        if (!StringHelper.isEmpty(queryParam.getOrderBy())) {
            if (!StringHelper.isEmpty(queryParam.getOrderType()) && "asc".equals(queryParam.getOrderType())) {
                queryParam.setOrderBy("u." + queryParam.getOrderBy());
            } else {
                queryParam.setOrderType("desc");
                queryParam.setOrderBy("u." + queryParam.getOrderBy());
            }
        } else {
            queryParam.setOrderType("desc");
            queryParam.setOrderBy("u.user_name");
        }
        Long count = baseMapper.querySysUserListCount(queryParam);
        if (count > 0) {
            List<SysUserListResponse> records = baseMapper.querySysUserList(queryParam);
            resultPage.setRecords(records);
        }
        resultPage.setTotal(count);
        return resultPage;
    }

    @Override
    public boolean updateIamUser(String iamUserId) {
        IamUserQueryDto queryDto = new IamUserQueryDto();
        queryDto.setUserid(iamUserId);
        List<IamSysUser> users = requestIamUtil.getUser(queryDto);
        if (Objects.nonNull(users)) {
            IamSysUser user = users.get(0);
            IamSysUser old = getById(user.getId());
            if (Objects.nonNull(old)) {
                user.setCreateDate(old.getCreateDate());
                old.setUpdateDate(new Date());
            } else {
                user.setCreateDate(new Date());
            }
            return saveOrUpdate(user);
        }
        return false;
    }

    @Override
    public BaseResponse<List<SysUser>> getBindUserList(IamLoginDto iamLoginDto) {
        BaseResponse baseResponse = new BaseResponse();
        IamUserResponse iamUserResponse = new IamUserResponse();
        JSONObject token = requestIamUtil.getToken(iamLoginDto);
        if (Objects.isNull(token)) {
            baseResponse.setCode(IamErrorEnum.CALL_IAM_FAILED.code());
            baseResponse.setMsg(IamErrorEnum.CALL_IAM_FAILED.msg());
        } else if (Objects.isNull(token.get("id_token"))) {
            baseResponse.setCode(IamErrorEnum.EXCHANGE_FAILED.code());
            baseResponse.setMsg(IamErrorEnum.EXCHANGE_FAILED.msg());
            log.info("code交换用户信息失败：{}", token.toJSONString());
        } else {
            JwtClaims jwtClaims = null;
            try {
                jwtClaims = requestIamUtil.validateToken(iamLoginDto.getType(), String.valueOf(token.get("id_token")));
            } catch (Exception e) {
                baseResponse.setCode(IamErrorEnum.VALIDATION_FAILED.code());
                baseResponse.setMsg(IamErrorEnum.VALIDATION_FAILED.msg());
            }
        String iamUserId = String.valueOf(jwtClaims.getClaimValue("sub"));
        //String iamUserId = "zuoyuxiang";
        //String iamUserId = "caoxiangjin6";
        List<IamUserMapping> byIamUserId = iamUserMappingService.getByIamUserId(iamUserId);
        if (CollectionUtils.isEmpty(byIamUserId)) {
            baseResponse.setCode(IamBindStatusEnum.UNBOUND.code());
            baseResponse.setMsg(IamBindStatusEnum.UNBOUND.msg());
            iamUserResponse.setIamUserId(iamUserId);
            baseResponse.setData(iamUserResponse);
            return baseResponse;
        }
        List<SysUser> sysUsers = new ArrayList<>();

        for (IamUserMapping iamUserMapping : byIamUserId) {
            SysUser byId = sysUserService.getById(iamUserMapping.getUserId());
            //添加验证id
            String uuid = UUID.randomUUID().toString();
            redisTemplate.opsForValue().set(uuid, byId.getUserId(),2, TimeUnit.MINUTES);
            byId.setUserKeyPid(uuid);
            sysUsers.add(byId);
        }
        iamUserResponse.setIamUserId(iamUserId);
        iamUserResponse.setSysUsers(sysUsers);
        baseResponse.setData(iamUserResponse);

        }
        return baseResponse;
    }

    @Override
    public List<SysUser> getUserByIamId(String iamId) {
        List<SysUser> sysUsers = new ArrayList<>();
        //获取用户
        List<IamUserMapping> byIamUserId = iamUserMappingService.getByIamUserId(iamId);
        for (IamUserMapping iamUserMapping : byIamUserId) {
            SysUser byId = sysUserService.getById(iamUserMapping.getUserId());
            sysUsers.add(byId);
        }
        return sysUsers;
    }

    @Override
    public IPage<SysUserListResponse> pageUserList(SysUserParam param) {
        Page<SysUserListResponse> resultPage = new Page<>(param.getPage(), param.getLimit());
        return baseMapper.pageUserList(resultPage, param);
    }

    @Override
    public void export(SysUserParam param,  List<String> cols,  List<String> ids, HttpServletResponse response) {
        QueryWrapper<SysUser> queryWrapper = this.createQuery(param);
        if (ObjectHelper.isNotEmpty(ids) && !ids.isEmpty()) {
            queryWrapper.in("user_id", ids);
        }
        List<SysUser> resultList = this.sysUserService.list(queryWrapper);
        List<SysUserListResponse> records = resultList.stream().map((bean) -> {
            return bean.beanToBean(SysUserListResponse.class);
        }).collect(Collectors.toList());
        List<UserExport> userExports = records.stream().map((e) -> {
            return  BeanHelper.beanToBean(e, UserExport.class);
        }).peek(UserExport::convertSex).collect(Collectors.toList());
        Iterator var10 = userExports.iterator();

        while(var10.hasNext()) {
            UserExport userExport = (UserExport)var10.next();
            userExport.setOrgName(this.sysOrgService.getOrgFullPathName(userExport.getOrgId()));
        }

        try {
            this.export("用户信息数据-" + DatetimeHelper.getDateTime8Length(), userExports, UserExport.class, response, cols);
        } catch (IOException var12) {
            log.error("Export Error ", var12);
            throw new ApiException(ExcelEnum.EXPORT_ERROR.transform());
        }
    }

    private QueryWrapper<SysUser> createQuery(SysUserParam queryParam) {
        QueryWrapper<SysUser> queryWrapper = new QueryWrapper();
        if (!StringHelper.isEmpty(queryParam.getLoginName())) {
            queryWrapper.like("login_name", queryParam.getLoginName());
        }

        if (!StringHelper.isEmpty(queryParam.getUserName())) {
            queryWrapper.like("user_name", queryParam.getUserName());
        }

        if (!StringHelper.isEmpty(queryParam.getPhoneNo())) {
            queryWrapper.like("phone_no", queryParam.getPhoneNo());
        }

        if (!StringHelper.isEmpty(queryParam.getUserType())) {
            queryWrapper.eq("user_type", queryParam.getUserType());
        }

        if (!StringHelper.isEmpty(queryParam.getOrgIdList())) {
            queryWrapper.in("org_id", queryParam.getOrgIdList());
        }

        if (StringHelper.isEmpty(queryParam.getStatus())) {
            queryWrapper.in("status", Arrays.asList("0", "2"));
        } else if (!"1".equals(queryParam.getStatus())) {
            queryWrapper.eq("status", queryParam.getStatus());
        }

        if (!StringHelper.isEmpty(queryParam.getOrderBy())) {
            if (!StringHelper.isEmpty(queryParam.getOrderType()) && "asc".equals(queryParam.getOrderType())) {
                queryWrapper.orderByAsc(queryParam.getOrderBy());
            } else {
                queryWrapper.orderByDesc(queryParam.getOrderBy());
            }
        } else {
            queryWrapper.orderByDesc("user_name");
        }

        return queryWrapper;
    }


    public <T> void export(String fileName, List<T> data, Class<?> dataType, HttpServletResponse response, List<String> cols) throws IOException {
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        fileName = URLEncoder.encode(fileName, "UTF-8");
        fileName = StringHelper.replace(fileName, "+", "%20");
        response.setHeader("Access-Control-Expose-Headers", "Content-disposition");
        response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
        if (ObjectHelper.isNotEmpty(cols)) {
            Set<String> includeColumnFiledNames = new HashSet<>(cols);
            ( EasyExcel.write(response.getOutputStream(), dataType).includeColumnFiledNames(includeColumnFiledNames)).sheet("数据").doWrite(data);
        } else {
            EasyExcel.write(response.getOutputStream(), dataType).sheet("数据").doWrite(data);
        }

    }


}
