package com.repair.controller;

import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.repair.annotation.PassToken;
import com.repair.api.LoginControllerAPI;
import com.repair.common.utils.AesUtils;
import com.repair.common.utils.HttpsClient;
import com.repair.common.utils.JWTUtil;
import com.repair.common.utils.paramUtils;
import com.repair.config.WxOpenidConfig;
import com.repair.model.enumModel.eSchool;
import com.repair.model.enumModel.eStatu;
import com.repair.model.enumModel.eUserZZ;
import com.repair.model.pojo.RepairAdmin;
import com.repair.model.pojo.RepairUser;
import com.repair.model.request.changePasswordRequest;
import com.repair.model.request.loginRequest;
import com.repair.model.result.CommonResult;
import com.repair.model.result.Wx_user;
import com.repair.model.vo.*;
import com.repair.services.RepairAdminService;
import com.repair.services.RepairUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RestController;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Author: binguo
 * @Date: 2023/7/5 星期三 9:28
 * @Description: com.template.controller
 * @Version: 1.0
 */
@RestController
public class LoginController implements LoginControllerAPI {

    @Autowired
    private WxOpenidConfig wxOpenidConfig;
    @Autowired
    private RepairUserService repairUserService;
    @Autowired
    private RepairAdminService repairAdminService;

    /**
     * 查看系统版本号
     *
     * @return
     */
    @Override
    @PassToken
    public CommonResult queryReduce() {
        return CommonResult.ok("ip地址为" + wxOpenidConfig.getIpconfig() + "的系统版本为：4V");
    }

    /**
     * 注册接口
     *
     * @param registerdo account 账号
     *                   password 密码
     *                   username 昵称
     *                   phone 手机号
     * @return
     */
    @Override
    @PassToken
    public CommonResult Register(@RequestBody RepairAdmin registerdo, BindingResult bindingResult) {

        if (registerdo == null) {
            return CommonResult.fail("请传递参数");
        }
        if (bindingResult.hasErrors()) {
            String st = paramUtils.getParamError(bindingResult);
            return CommonResult.fail(st);
        }

        RepairAdmin data = repairAdminService.getRepairByAccount(registerdo.getAccount());
        if (data != null) {
            return CommonResult.fail("该账号已存在！");
        }

        int result = repairAdminService.insertRepairAdmin(registerdo);

        if (result > 0) {
            return CommonResult.ok("注册成功！");
        }
        return CommonResult.fail("注册失败！");
    }

    /**
     * 登录接口
     *
     * @param loginRequest account 账号
     *                     password 密码
     * @return
     */
    @Override
    @PassToken
    public CommonResult Login(@RequestBody loginRequest loginRequest, BindingResult bindingResult) {
        if (loginRequest == null) {
            return CommonResult.fail("请传递参数");
        }
        if (bindingResult.hasErrors()) {
            String st = paramUtils.getParamError(bindingResult);
            return CommonResult.fail(st);
        }

        RepairAdmin result = repairAdminService.getRepairByAccount(loginRequest.getAccount());
        if (result == null) {
            return CommonResult.fail("账号或密码错误");
        }

        if (result.getStatu().equals(eStatu.Freeze.getValue())) {
            return CommonResult.fail("该账号已被冻结");
        }

        String encPassword = AesUtils.encrypt(loginRequest.getPassword());
        if (!encPassword.equals(result.getPassword())) {
            return CommonResult.fail("密码错误");
        }

        String token = JWTUtil.getToken(result, null);
        LoginVo login = new LoginVo();
        login.setSchoolId(result.getIsSuper() == 1 ? 0 : result.getSchoolId());
        login.setToken(token);
        login.setTokenTtl(JWTUtil.getExpired());
        login.setUserName(result.getUsername());
        login.setUserhead(AesUtils.encrypt(result.getId()));

        //要在账户表中添加一条对应的数据

        return CommonResult.ok("登录成功", login);
    }

    /**
     * 修改密码
     *
     * @param cpr           oldPassword 旧密码
     *                      newPassword 新密码
     *                      confirmPassword 确认密码
     * @param userhead
     * @param bindingResult
     * @return
     */
    @Override
    public CommonResult ChangePassword(changePasswordRequest cpr, @RequestHeader("user_head") String userhead, BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            String st = paramUtils.getParamError(bindingResult);
            return CommonResult.fail(st);
        }

        if (!cpr.getNewPassword().equals(cpr.getConfirmPassword())) {
            return CommonResult.fail("确认密码和新密码不一致！");
        }

        String userID = AesUtils.decrypt(userhead);
        RepairAdmin operateData = repairAdminService.getRepairById(userID);
        if (operateData == null) {
            return CommonResult.fail("当前账号不合法！");
        }

        if (operateData.getStatu() == eStatu.Freeze.getValue()) {
            return CommonResult.fail("该账号已被冻结");
        }

        if (!AesUtils.encrypt(cpr.getOldPassword()).equals(operateData.getPassword())) {
            return CommonResult.fail("原密码错误！");
        }

        RepairAdmin ra = new RepairAdmin();
        ra.setId(userID);
        ra.setPassword(AesUtils.encrypt(cpr.getNewPassword()));
        int result = repairAdminService.updateRepairAdmin(ra);

        return result > 0 ? CommonResult.ok("修改成功") : CommonResult.fail("修改失败");
    }

    @Override
    @PassToken
    @Transactional(rollbackFor = {Exception.class})
    public CommonResult Openid(String wxcode) throws Exception {
        System.out.println("微校授权：" + wxcode);
        Gson gson = new Gson();
        String tokenUrl = "https://open.wecard.qq.com/connect/oauth2/token";
        Map<String, String> tokenParams = new HashMap<>();
        String url = "mnp://" + wxOpenidConfig.getXappid();
        tokenParams.put("wxcode", wxcode);
        tokenParams.put("app_key", wxOpenidConfig.getAppid());
        tokenParams.put("app_secret", wxOpenidConfig.getAppkey());
        tokenParams.put("grant_type", wxOpenidConfig.getGranttype());
        tokenParams.put("redirect_uri", url); // 小程序为 mnp:// + 小程序app id
        System.out.println("微校授权1：");
        // wecode换取token
        String respon = HttpsClient.post(tokenUrl, tokenParams);
        System.out.println("微校授权2：" + respon);
        if (!StringUtils.hasText(respon)) {
            System.out.println("微校授权异常信息：respon为空" + respon);
            return CommonResult.fail("微校授权异常信息");
        }
        HashMap<String, Object> tokenMap = gson.fromJson(respon, new TypeToken<HashMap<String, Object>>() {
        }.getType());
        System.out.println("微校授权3");
        String accessToken = (String) tokenMap.get("access_token");
        System.out.println("微校授权4");
        // token换取用户信息
        String userInfoUrl = "https://open.wecard.qq.com/connect/oauth/get-user-info";
        System.out.println("微校授权5");
        Map<String, String> userInfoParam = new HashMap<>();
        System.out.println("微校授权6");
        userInfoParam.put("access_token", accessToken);
        System.out.println("微校授权7");
        String userinfo = HttpsClient.post(userInfoUrl, userInfoParam);
        System.out.println("微校授权8");
        String card_number = null;
        String user_name = null;
        String phone = null;
        int identity_type = 0;
        String college = null;
        String grade = null;
        String profession = null;
        String campus = null;
        Wx_user userinfos = gson.fromJson(userinfo, new TypeToken<Wx_user>() {
        }.getType());
        System.out.println("微校授权9");
        System.out.println("微校授权获取用户信息：" + userinfo);
        System.out.println("微校授权获取用户信息类别：" + userinfos.getIdentity_type());
        try {
            card_number = userinfos.getCard_number();
            user_name = userinfos.getName();
            phone = userinfos.getTelephone();
            identity_type = userinfos.getIdentity_type();
            college = userinfos.getCollege();
            grade = userinfos.getGrade();
            profession = userinfos.getProfession();
            campus = userinfos.getCampus();

        } catch (Exception e) {
            System.out.println("微校授权异常信息：" + e.getMessage());
            return CommonResult.fail(e.getMessage());
        }

        if (card_number == null || card_number.equals("")) {
            return CommonResult.fail("卡号为空，授权失败");
        }
        //根据卡号查询repair_user表中的用户信息
        RepairUser user = repairUserService.getRepairByCardNumber(card_number);
        //取消授权的身份验证 谁都能进
        //if (identity_type != 4 && user == null) {
        //   return CommonResult.fail("非法权限，授权失败");
        //}

        System.out.println("微校授权校区：" + campus);
        System.out.println("微校授权校区ID：" + eSchool.integerOf(campus));

        if (user == null) {
            try {
                user = new RepairUser();
                user.setCardNumber(card_number);
                user.setUserName(user_name);
                user.setUserPhone(phone);
                user.setUserZzid(eUserZZ.User.getValue());
                user.setIdentityType(identity_type);
                user.setCollege(college);
                user.setGrade(grade);
                user.setProfession(profession);
                user.setSchoolId(ObjectUtils.isEmpty(campus) ? 1 : eSchool.integerOf(campus));//校区ID
                user.setIsChange(0);
                int num = repairUserService.insertRepairUser(user);
                if (num <= 0) {
                    System.out.println("微校授权失败，用户信息新增异常：" + user_name + "" + card_number);
                    throw new Exception("微校授权失败！");
                }

            } catch (Exception e) {
                System.out.println("微校授权异常信息：" + e.getMessage());
                throw new Exception("微校授权失败！");
            }
        } else {
            //更新微校获取的年纪信息
            user.setCollege(college);
            user.setGrade(grade);
            user.setProfession(profession);

            int num = repairUserService.updateRepairUser(user);
            if (num <= 0) {
                System.out.println("微校授权失败，用户信息新增异常：" + user_name + "" + card_number);
                throw new Exception("微校授权失败！");
            }
        }

        RepairAdmin admin = repairAdminService.getRepairByCardnumber(card_number);
        if (admin == null) {
            try {
                admin = new RepairAdmin();
                admin.setAccount(card_number);
                admin.setPassword("974264710");
                admin.setUsername(user_name);
                admin.setPhone(phone);
                admin.setIsSuper(0);
                admin.setStatu(1);
                admin.setSchoolId(ObjectUtils.isEmpty(campus) ? 1 : eSchool.integerOf(campus));
                admin.setCardNumber(card_number);
                admin.setIsMobile(1);
                int adminNum = repairAdminService.insertRepairAdmin(admin);
                if (adminNum <= 0) {
                    System.out.println("微校授权失败，管理端信息新增异常：" + user_name);
                    return CommonResult.fail("无法记录账号信息，授权失败");
                }
            } catch (Exception e) {
                System.out.println("微校授权异常信息：" + e.getMessage());
                throw new Exception("微校授权失败！");
            }
        }

        wxLoginVo wlv = new wxLoginVo();
        routeDataVo data = getRoutes(user.getUserZzid());
        wlv.setUserId(user.getId());
        wlv.setRoutes(data == null ? new ArrayList<>() : data.getRoutes());
        wlv.setBtns(data == null ? new ArrayList<>() : data.getBtns());
        wlv.setUserName(user.getUserName());
        wlv.setUserPhone(user.getUserPhone().replace("(+86)", ""));
        wlv.setUserZZid(user.getUserZzid());
        wlv.setUserZZName(eUserZZ.stringOf(user.getUserZzid()));
        wlv.setSchoolId(user.getSchoolId());
        wlv.setSchoolName(eSchool.stringOf(user.getSchoolId()));
        wlv.setCollege(college == null ? "微校获取不到院校" : college);
        long expired = 1000 * 60 * 60 * 24 * 365;
        String token = JWTUtil.getToken(admin, expired);
        wlv.setToken(token);
        wlv.setUserhead(AesUtils.encrypt(admin.getId()));
        System.out.println("微校授权成功：" + user_name + "" + card_number);
        return CommonResult.ok(wlv);
    }

    /**
     * 获取小程序code换取openid、session_key
     * userId：用户ID
     *
     * @param code
     * @return
     */
    @Override
    @PassToken
    public CommonResult XOpenid(String code, Integer userId) {
        WxOpenVo wov = new WxOpenVo();

        RepairUser user = repairUserService.getRepairById(userId);
        if (user == null) {
            return CommonResult.fail("用户信息不合法，无法进行微信授权");
        }

        if (user.getOpenid() != null) {
            wov.setOpenId(user.getOpenid());
            return CommonResult.ok(wov);
        }

        String url = "https://api.weixin.qq.com/sns/jscode2session?appid=" + wxOpenidConfig.getXappid()
                + "&secret=" + wxOpenidConfig.getXsecret() + "&js_code=" + code + "&grant_type=authorization_code";
        PrintWriter out = null;
        BufferedReader in = null;
        String line;
        StringBuffer stringBuffer = new StringBuffer();
        try {
            URL realUrl = new URL(url);
            // 打开和URL之间的连接
            URLConnection conn = realUrl.openConnection();

            // 设置通用的请求属性 设置请求格式
            //设置返回类型
            conn.setRequestProperty("contentType", "text/plain");
            //设置请求类型
            conn.setRequestProperty("content-type", "application/x-www-form-urlencoded");
            //设置超时时间
            conn.setConnectTimeout(1000);
            conn.setReadTimeout(1000);
            conn.setDoOutput(true);
            conn.connect();
            // 获取URLConnection对象对应的输出流
            out = new PrintWriter(conn.getOutputStream());
            // flush输出流的缓冲
            out.flush();
            // 定义BufferedReader输入流来读取URL的响应    设置接收格式
            in = new BufferedReader(
                    new InputStreamReader(conn.getInputStream(), "UTF-8"));
            while ((line = in.readLine()) != null) {
                stringBuffer.append(line);
            }
            WxCodeVo entity = new WxCodeVo();
            JSONObject wx = JSONObject.parseObject(stringBuffer.toString());

            // json数据转换成字符串
            assert wx != null;
            String openid = wx.get("openid").toString();
            String sessionkey = wx.get("session_key").toString();
            // 当主体账户绑定小程序后就可以获取到，未绑定无法获取
            String unionId = "";
            if (wx.get("unionid") != null) {
                unionId = wx.get("unionid").toString();
            }
            entity.setOpenid(openid);
            entity.setSessionkey(sessionkey);
            entity.setUnionid(unionId);

            //根据用户ID找到用户数据 并把openid绑定进去
            user.setOpenid(openid);
            int updateUser = repairUserService.updateRepairUser(user);
            if (updateUser <= 0) {
                return CommonResult.fail("更新用户openid失败");
            }

            wov.setOpenId(user.getOpenid());

            return CommonResult.ok(wov);

        } catch (Exception e) {
            e.printStackTrace();
        }
        //使用finally块来关闭输出流、输入流
        finally {
            try {
                if (out != null) {
                    out.close();
                }
                if (in != null) {
                    in.close();
                }
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }

        return CommonResult.ok(wov);
    }

    /**
     * 获取移动端路由
     *
     * @param userZZid 用户身份ID
     * @return
     */
    public routeDataVo getRoutes(Integer userZZid) {
        routeDataVo result = new routeDataVo();
        List<String> routes = new ArrayList<>();
        List<String> btns = new ArrayList<>();
        switch (userZZid) {
            //维修师傅
            //eUserZZ.Maintenance.getValue()：1
            case 1:
                routes.add("首页");
                routes.add("工单管理");
                routes.add("待处理池");

                btns.add("协作");
                btns.add("接单");
                btns.add("转单");
                btns.add("报价");
                btns.add("维修完成");
                break;
            //管理者（郭班长）
            //eUserZZ.Monitor.getValue()：2
            case 2:
                routes.add("首页");
                routes.add("工单管理");
                routes.add("待处理池");
                routes.add("通讯录");

                btns.add("首页分段器");
                btns.add("表格编辑");
                btns.add("工单管理分段器");
                btns.add("延时");
                btns.add("审核");
                btns.add("接单");
                btns.add("报价");
                btns.add("维修完成");
                btns.add("派单");
                btns.add("图表");
                btns.add("协作");
                btns.add("转单");
                break;
            //后勤
            //eUserZZ.Logistics.getValue()：3
            case 3:
                routes.add("首页");
                routes.add("工单管理");
                routes.add("待处理池");
                routes.add("通讯录");

                btns.add("表格编辑");
                btns.add("延时");
                btns.add("派单");
                btns.add("图表");
                btns.add("审核");
                btns.add("分段器按钮");
                break;
            //用户（默认都是用户）
            //eUserZZ.User.getValue()：0
            default:
                routes.add("报修");
                routes.add("我的报修");
                break;
        }
        result.setRoutes(routes);
        result.setBtns(btns);

        return result;
    }
}
