package cn.cslg.pas.service;

import cn.cslg.pas.common.core.base.Constants;
import cn.cslg.pas.common.core.base.RedisConf;
import cn.cslg.pas.common.model.PersonnelVO;
import cn.cslg.pas.common.model.dto.ClientDTO;
import cn.cslg.pas.common.model.dto.PasUserDTO;
import cn.cslg.pas.common.utils.*;
import cn.cslg.pas.common.utils.SecurityUtils.LoginUtils;
import cn.cslg.pas.domain.Project;
import cn.cslg.pas.domain.ProjectUser;
import cn.cslg.pas.domain.User;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.CircleCaptcha;
import cn.hutool.core.img.ImgUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.crypto.SecureUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.google.gson.Gson;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
@Slf4j
@RequiredArgsConstructor(onConstructor_ = {@Lazy})
public class OAuth2Service {

    private final UserService userService;
    private final CacheUtils cacheUtils;
    private final RedisUtil redisUtil;
    private final ProjectUserService projectUserService;
    private final ProjectService projectService;
    private final LoginUtils loginUtils;
    private final RequestService requestService;
    @Value("${authorUrl}")
    private String url;
    public static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");

    public PersonnelVO getUserinfo() {
        Integer userId = loginUtils.getId();
        PersonnelVO personnelVO = cacheUtils.getLoginUser(userId);
        personnelVO.setPassword(null);
        return personnelVO;
    }

    public Map<Integer, Integer> getPermissions() throws IOException {
        log.info("开始获得权限");
        Map<Integer, Integer> result = new HashMap<>();
        //获取登录人的信息
        PersonnelVO user = this.getUserinfo();
        //当登录人的姓账号为admin时，给登录人赋予所有专题库的管理员权限
        if (user.getUsername().equals(Constants.ADMIN_USERNAME)) {
            List<Project> projectList = projectService.list();
            for (Project project : projectList) {
                result.put(project.getId(), 0);
            }
            return result;
        }
        log.info("开始查询专题库信息");
        List<ProjectUser> projectUserList = projectUserService.getProjectUserByUserId(user.getId());
        log.info("查询专题库信息");
        List<Project> projectList = projectService.getProjectByIds(projectUserList.stream().map(ProjectUser::getProjectId).collect(Collectors.toList()));
        List<Project> createProject = projectService.getProjectByCreateId(user.getId());
        List<Project> projects = new ArrayList<>();
        Set<Integer> projectIds = new HashSet<>();
        projects.addAll(projectList);
        projects.addAll(createProject);
        projects.forEach(item -> projectIds.add(item.getId()));
        for (Integer projectId : projectIds) {
            Integer userType;
            Project project = projects.stream().filter(item -> item.getId().equals(projectId)).findFirst().orElse(new Project());
            if (project.getCreateBy().equals(user.getId())) {
                userType = 0;
            } else {
                ProjectUser projectUser = projectUserList.stream().filter(item -> item.getProjectId().equals(projectId)).findFirst().orElse(new ProjectUser());
                userType = projectUser.getType();
            }
            result.put(projectId, userType);
        }
        return result;
    }

    public String getTokenByUsername(String username, String password, String code, String uuid) {
        String tempCode = redisUtil.get(RedisConf.VERIFY_CODE + RedisConf.SYMBOL_COLON + uuid);
        if (StringUtils.isEmpty(tempCode) || !tempCode.equals(code)) {
            return Response.error(ResponseEnum.VERIFY_CODE_ERROR);
        }
        User user = userService.getByUsername(username);
        if (user == null) {
            return Response.error(ResponseEnum.USERNAME_ERROR);
        }
        boolean isPassword = SecureUtil.md5(password).equals(user.getPassword());
        if (!isPassword) {
            return Response.error(ResponseEnum.PASSWORD_ERROR);
        }
        StpUtil.login(user.getId());
        cacheUtils.setLoginUser(user);
        user.setPassword(null);
        return Response.success(user);
    }

    public String getVerifyCode(HttpServletRequest request, HttpServletResponse response) throws Exception {
        //定义图形验证码的长、宽、验证码字符数、干扰元素个数
        CircleCaptcha captcha = CaptchaUtil.createCircleCaptcha(200, 100, 4, 20);
        String uuid = UUID.fastUUID().toString();
        Map<String, String> result = new HashMap<>();
        result.put("captcha", ImgUtil.toBase64DataUri(captcha.getImage(), "png"));
        result.put("uuid", uuid);
        redisUtil.setEx(RedisConf.VERIFY_CODE + RedisConf.SYMBOL_COLON + uuid, captcha.getCode(), 60, TimeUnit.SECONDS);
        return Response.success(result);
    }

    /**
     * @return 1.生成验证码的base64转码 2.生成的UUID 与Redis里面的验证码KEY值一致
     * @author 沈永艺
     */
    public String verifyCode() throws Exception {
        String resBody = requestService.getVerifyCodeFromPCS();
        JSONObject jsonObject = JSONObject.parseObject(resBody);
        JSONObject data = (JSONObject) jsonObject.get("data");
        Object captcha = data.get("captcha");
        Object uuid = data.get("uuid");
        Map<String, String> result = new HashMap<>();
        result.put("captcha", captcha.toString());
        result.put("uuid", uuid.toString());
        return Response.success(result);
    }

    /**
     * @return 登录成功的信息
     * @author 沈永艺
     */
    public String login(String username, String password, String code, String uuid) throws IOException {
        String resBody = requestService.LoginFromPCS(username, password, code, uuid);
        JSONObject jsonObject = JSONObject.parseObject(resBody);
        //判断请求返回是否为200，不是的话则返回报错信息
        if (!jsonObject.get("code").equals(200)) {
            return Response.error(jsonObject.get("message").toString());

        }
        String token = jsonObject.get("data").toString();
        PersonnelVO personnelVO = com.alibaba.fastjson2.JSONObject.parseObject(token, PersonnelVO.class);

        token = personnelVO.getToken();
        String q = "token:login:token:" + token;
        String IdS = redisUtil.get(q);
        PersonnelVO personnelVO2 = cacheUtils.getLoginUser(IdS);
        String tenantType = personnelVO2.getTenantType();
        HashMap<Object, Object> loginMap = new HashMap<>();
        loginMap.put("token", token);
        loginMap.put("tenantType", tenantType);
        return Response.success(loginMap);
    }

    public String changePwd(String oldPassword, String newPassword) {
        Integer userId = loginUtils.getId();
        User user = userService.getById(userId);
        boolean isPassword = SecureUtil.md5(oldPassword).equals(user.getPassword());
        if (!isPassword) {
            return Response.error("旧密码错误");
        }
        user.setPassword(SecureUtil.md5(newPassword));
        user.updateById();
        return Response.success(true);
    }

    /**
     * @title 获得专题库成员列表
     * @description 获得专题库成员列表
     * @autor lrj
     */

    public String getPASAssignedUser(PasUserDTO params) throws IOException {
        OkHttpClient okHttpClient = new OkHttpClient();
        String param = new Gson().toJson(params);
        RequestBody requestBody = RequestBody.create(MediaType.parse("application/json"), param);
        Request request = new Request.Builder()
                .url(url + "/permission/api/system/getPASAssignedUser")
                .post(requestBody)
                .build();
        return Objects.requireNonNull(okHttpClient.newCall(request).execute().body()).string();
    }


}
