package com.huiju.estateagents.controller;

import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
import cn.binarywang.wx.miniapp.bean.WxMaUserInfo;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.huiju.estateagents.base.BaseController;
import com.huiju.estateagents.base.ResponseBean;
import com.huiju.estateagents.center.sysUser.service.ISysTokenService;
import com.huiju.estateagents.center.taUser.entity.TaUser;
import com.huiju.estateagents.center.taUser.service.ITaUserService;
import com.huiju.estateagents.common.CommConstant;
import com.huiju.estateagents.common.JWTUtils;
import com.huiju.estateagents.common.StringUtils;
import com.huiju.estateagents.drainage.entity.TaDrainage;
import com.huiju.estateagents.drainage.service.ITaDrainageService;
import com.huiju.estateagents.entity.*;
import com.huiju.estateagents.event.EventBus;
import com.huiju.estateagents.mapper.TaOrgCityMapper;
import com.huiju.estateagents.mapper.TaSalesBatchMapper;
import com.huiju.estateagents.property.model.TaUserVerify;
import com.huiju.estateagents.property.service.ITaUserVerifyService;
import com.huiju.estateagents.redpack.service.ITaMpMiniappService;
import com.huiju.estateagents.service.*;
import com.huiju.estateagents.third.service.ITaThirdPartyMiniappConfigService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import me.chanjar.weixin.common.error.WxErrorException;
import org.apache.commons.collections.CollectionUtils;
import org.apache.http.HttpStatus;
import org.checkerframework.checker.units.qual.A;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Array;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collector;
import java.util.stream.Collectors;

import static com.sun.jmx.snmp.ThreadContext.contains;

@RestController
@RequestMapping("/api/wx")
@Api(value = "微信登录相关", tags = "微信登录相关")
public class MiniAppController extends BaseController {

    private Logger logger = LoggerFactory.getLogger(MiniAppController.class);

    @Autowired
    private ITaPersonService taPersonService;

    @Autowired
    private IMiniAppService miniAppService;

    @Autowired
    private ITaRecommendCustomerService taRecommendCustomerService;

    @Resource
    private ApplicationContext applicationContext;

    @Autowired
    private ITaOrgService taOrgService;

    @Autowired
    private ISysTokenService sysTokenService;

    @Autowired
    private ITaMiniappService taMiniappService;

    @Autowired
    private ITaSharePersonFromService taSharePersonFromService;

    @Autowired
    private ITaBuildingDynamicService buildingDynamicService;

    @Autowired
    private ITaNewsService newsService;

    @Autowired
    private ITaUserService userService;

    @Autowired
    private ITaPersonBuildingService personBuildingService;

    @Autowired
    public ITaThirdPartyMiniappConfigService iTaThirdPartyMiniappConfigService;

    @Autowired
    private ITaCustomImgService iTaCustomImgService;

    @Autowired
    public ITdPointsRulesService iTdPointsRulesService;

    @Autowired
    public ITaMiniappService iTaMiniappService;

    @Autowired
    public TaOrgCityMapper taOrgCityMapper;

    @Autowired
    public ITdCityService iTdCityService;

    @Autowired
    private IHelpActivityService helpActivityService;

    @Autowired
    private ITaShareActivityService taShareActivityService;

    @Autowired
    private ITaLiveActivityService taLiveActivityService;

    @Autowired
    private ITaDrainageService taDrainageService;

    @Autowired
    private TaSalesBatchMapper taSalesBatchMapper;

    @Autowired
    private ITaUserVerifyService taUserVerifyService;

    @Autowired
    private ITaMpMiniappService iTaMpMiniappService;

    /**
     * 验证接入
     */
    @GetMapping(value = "/", produces = "text/plain;charset=utf-8")
    public String access(@RequestParam(name = "signature", required = false) String signature,
                         @RequestParam(name = "timestamp", required = false) String timestamp,
                         @RequestParam(name = "nonce", required = false) String nonce,
                         @RequestParam(name = "echostr", required = false) String echostr) {
        return echostr;
    }


    /**
     * 小程序数据预拉取 https://developers.weixin.qq.com/miniprogram/dev/framework/ability/pre-fetch.html
     *
     * @param appid
     * @param timestamp
     * @param token
     * @param code
     * @param path
     * @param query
     * @param scene
     * @return
     */
    @GetMapping("/preload")
    public ResponseBean getPreloadData(
            @RequestParam(name = "appid") String appid,
            @RequestParam(name = "timestamp") Long timestamp,
            String token,
            String code,
            String path,
            String query,
            Integer scene
    ) {
        Map<String, Object> resp = new HashMap<>();

        // 获取小程序信息
        TaMiniapp taMiniapp = iTaMiniappService.getInfoWithTpls(appid);
        resp.put("miniapp", taMiniapp);
        if (null == taMiniapp) {
            return ResponseBean.error("当前 appid 未在系统内注册", ResponseBean.ERROR_ILLEGAL_PARAMS);
        }

        // 获取组织信息
        TaOrg taOrg = taOrgService.getById(taMiniapp.getOrgId());
        resp.put("org", taOrg);
        if (null == taOrg) {
            return ResponseBean.error("当前 appid 未设置对应组织", ResponseBean.ERROR_UNAVAILABLE);
        }

        //把積分規則返回給小程序
        QueryWrapper<TdPointsRules> tdPointsRulesQueryWrapper = new QueryWrapper<>();
        tdPointsRulesQueryWrapper.eq("org_id", taOrg.getOrgId());
        List<TdPointsRules> rulesPointList = iTdPointsRulesService.list(tdPointsRulesQueryWrapper);
        resp.put("pointRuleList", rulesPointList);

        return ResponseBean.success(resp);
    }

    /**
     * 登陆接口
     */
    @ApiOperation(value = "小程序登录", notes = "小程序登录")
    @PostMapping("/login")
    public ResponseBean login(
            String code,
            @RequestParam(required = false) String from,
            @RequestParam(required = false) String recommender,
            @RequestParam(required = false) String mpOpenId,
            @RequestParam(required = false) String targetId,
            @RequestParam(required = false) Integer scene,
            HttpServletRequest request) {
        String appid = request.getHeader("appid");

        if (StringUtils.isEmpty(code)) {
            return ResponseBean.error("参数 code 不能为空", ResponseBean.ERROR_ILLEGAL_PARAMS);
        }
        if (StringUtils.isEmpty(appid)) {
            return ResponseBean.error("Header 参数 appid 不能为空", ResponseBean.ERROR_ILLEGAL_PARAMS);
        }

        // 校验服务过期日期等
        ResponseBean checkResp = checkMiniappStatus(appid);
        if (checkResp != null) {
            return checkResp;
        }

        try {
            TaMiniapp miniapp = taMiniappService.getById(appid);
            WxMaJscode2SessionResult session = miniAppService.getSessionInfo(code, appid);
            Integer orgId = miniapp.getOrgId();

            // 如果是扫码进来的
            Map<String, String> sceneParams = null;
            if (null != scene) {
                TaMiniappQrcode qrcode = miniAppService.getQrCodeBySerialNo(scene);
                if (null != qrcode) {
                    String paramStr = qrcode.getQrParams();
                    JSONObject params = JSON.parseObject(paramStr);
                    sceneParams = StringUtils.parseQuery(params.getString("scene"));

                    from = sceneParams.get("from");
                    recommender = sceneParams.get("recommender");
                    targetId = sceneParams.get("id");
                }
            }

            TaPerson taPerson = taPersonService.newPersonByOpenid(session.getOpenid(), miniapp, from, recommender);
            if (null == taPerson) {
                return ResponseBean.error("发生未知错误", ResponseBean.ERROR_UNAVAILABLE);
            }
            taPerson.setPassword(null);
            // 变换person的身份
            QueryWrapper<TaUser> taUserQueryWrapper = new QueryWrapper<>();
            taUserQueryWrapper.eq("phone",taPerson.getPhone());
            List<TaUser> userList = userService.list(taUserQueryWrapper);
            if (userList.size() > 0){
                TaUser taUser = userList.get(0);
                taPerson.setPersonType(taUser.getType());
            }
            taPersonService.updateById(taPerson);

            if (StringUtils.isEmpty(mpOpenId)) {
                iTaMpMiniappService.mpPerson(taPerson, mpOpenId);
            }

            Map<Object, Object> map = new HashMap<>();
            map.put("openId", session.getOpenid());
            map.put("orgId", orgId);
            map.put("personId", taPerson.getPersonId());

            String token = JWTUtils.newTokenByMap(map);
            sysTokenService.saveToken(token);

            if (!StringUtils.isEmpty(from) && !StringUtils.isEmpty(recommender) && !StringUtils.isEmpty(targetId)) {
                taSharePersonFromService.createBy(taPerson, from, recommender, targetId);
            }
            // 获取用户认证状态
            taPerson.setVerifyStatus(getVerifyStatus(taPerson));
            Map<String, Object> result = new HashMap<>();
            result.put("person", taPerson);
            result.put("sessionKey", session.getSessionKey());
            result.put("token", token);
            if (null != sceneParams) {
                result.put("scene", sceneParams);
            }

            return ResponseBean.success(result);
        } catch (WxErrorException e) {
            System.err.println(e.getError());
            return ResponseBean.error("解析小程序 code 失败", ResponseBean.ERROR_UNAVAILABLE);
        }
    }

//    @PostMapping("/share-person")
//    public ResponseBean sharePerson(@RequestParam(required = false) String from,
//                                    @RequestParam(required = false) String recommender,
//                                    @RequestParam(required = false) String targetId,
//                                    @RequestParam(required = false) Integer scene,
//                                    HttpServletRequest request) {
//        String openid = getOpenId(request);
//        List<TaPerson> persons = taPersonService.getPersonsByOpenId(openid);
//        if (null == persons || persons.size() < 1) {
//            return ResponseBean.error("校验人员信息出错", ResponseBean.ERROR_UNAVAILABLE);
//        }
//
//        // 如果是扫码进来的
//        Map<String, String> sceneParams = null;
//        if (null != scene) {
//            TaMiniappQrcode qrcode = miniAppService.getQrCodeBySerialNo(scene);
//            if (null != qrcode) {
//                String paramStr = qrcode.getQrParams();
//                JSONObject params = JSON.parseObject(paramStr);
//                sceneParams = StringUtils.parseQuery(params.getString("scene"));
//
//                from = sceneParams.get("from");
//                recommender = sceneParams.get("recommender");
//                targetId = sceneParams.get("id");
//            }
//        }
//
//        taSharePersonFromService.createBy(persons.get(0), from, recommender, targetId);
//
//        return ResponseBean.success("success");
//    }

    private ResponseBean checkMiniappStatus(String appid) {
        TaUser taUser = userService.getAdminByAppID(appid);

        if (null == taUser) {
            return ResponseBean.error("系统尚未添加管理员, 请联系相关人员", ResponseBean.ERROR_UNAVAILABLE);
        }

        if (null == taUser.getExpDate() || LocalDateTime.now().isAfter(taUser.getExpDate())) {
            return ResponseBean.error("系统服务已到期或者尚未设置到期日期", ResponseBean.ERROR_UNAVAILABLE);
        }

        if (null == taUser.getStatus() || CommConstant.STATUS_NORMAL != taUser.getStatus()) {
            return ResponseBean.error("系统服务被停止或者出现异常", ResponseBean.ERROR_UNAVAILABLE);
        }

        return null;
    }

    private boolean checkSharePersonFrom(String from, String personId, String targetId, Integer orgId) {
        QueryWrapper<TaSharePersonFrom> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("target_type", from);
        queryWrapper.eq("person_id", personId);
        queryWrapper.eq("target_id", targetId);
        queryWrapper.eq("org_id", orgId);
        List<TaSharePersonFrom> list = taSharePersonFromService.list(queryWrapper);
        if (list.size() > 0) {
            return false;
        }
        return true;
    }

    /**
     * 登陆接口
     */
    @PostMapping("/logout")
    public ResponseBean logout(HttpServletRequest request) {
        String openid = getOpenId(request);
        List<TaPerson> persons = taPersonService.getPersonsByOpenId(openid);
        if (null == persons || persons.size() == 0) {
            return ResponseBean.success("");
        }

        return ResponseBean.success("");
    }


    /**
     * 获取用户信息, 并写入内部人员表
     */
    @PostMapping("/signup")
    public ResponseBean info(@RequestBody String paramStr, HttpServletRequest request) {
        String appid = request.getHeader("appid");
        TaPerson person = null;
        TaMiniapp miniapp = taMiniappService.getById(appid);
        if (null == paramStr || "".equals(paramStr.trim()) || "{}".equals(paramStr.trim())) {
            String openid = getOpenId(request);
            List<TaPerson> taPersons = taPersonService.getPersonsByOpenId(openid);
            if (null == taPersons || taPersons.size() != 1) {
                return ResponseBean.error("验证人员信息失败", ResponseBean.ERROR_UNAVAILABLE);
            }
            person = taPersons.get(0);
        } else {

            JSONObject params = JSONObject.parseObject(paramStr);
            if (null == params) {
                return ResponseBean.error("校验参数失败", ResponseBean.ERROR_ILLEGAL_PARAMS);
            }

            String sessionKey = params.getString("sessionKey");
            String signature = params.getString("signature");
            String rawData = params.getString("rawData");
            String encryptedData = params.getString("encryptedData");
            String iv = params.getString("iv");

            // 用户信息校验
            if (!miniAppService.checkUserInfo(sessionKey, rawData, signature, appid)) {
                return ResponseBean.error("校验参数失败", ResponseBean.ERROR_ILLEGAL_PARAMS);
            }

            // 解密用户信息
            WxMaUserInfo userInfo = miniAppService.getUserInfo(sessionKey, encryptedData, iv, appid);

            // 更新或保存用户信息
            person = taPersonService.mergePersonWxInfo(userInfo);
            if (null == person) {
                return ResponseBean.error("发生未知错误", ResponseBean.ERROR_UNAVAILABLE);
            }
            taPersonService.upDatePersonCityToId(person.getPersonId());
        }

        // 获取其余信息
        Map<String, Object> extraInfo = taPersonService.getExtraInfo(person.getPersonId());
        person.setPassword(null);

        // 获取用户认证状态
        person.setVerifyStatus(getVerifyStatus(person));
        Map<String, Object> result = new HashMap<>();
        result.put("person", person);
        result.put("extraInfo", extraInfo);
        result.put("miniApp", miniapp);

        return ResponseBean.success(result);
    }

    private String getVerifyStatus(TaPerson person) {
        QueryWrapper<TaUserVerify> taUserVerifyQueryWrapper = new QueryWrapper<>();
        taUserVerifyQueryWrapper.eq("person_id",person.getPersonId());
        List<TaUserVerify> taUserVerifies = taUserVerifyService.list(taUserVerifyQueryWrapper);
        // 未认证
        String verifyStatus = "not_certified";
        List<String> verifyList = taUserVerifies.stream().map(TaUserVerify::getVerifyStatus).collect(Collectors.toList());
        if (verifyList.contains("1")){
            // 已认证
            verifyStatus = "certified";
        }else if (verifyList.contains("2")){
            // 认证未通过
            verifyStatus = "certification_failed";
        }else if (verifyList.contains("0")){
            // 认证中
            verifyStatus = "certification_in_progress";
        }
        return verifyStatus;
    }

    /**
     * 获取用户绑定手机号信息
     */
    @ApiOperation(value = "小程序授权手机号", notes = "小程序授权手机号")
    @PostMapping("/userPhone")
    public ResponseBean phone(@RequestBody String paramStr, HttpServletRequest request) {
        String appid = request.getHeader("appid");
        JSONObject params = JSONObject.parseObject(paramStr);
        if (null == params) {
            return ResponseBean.error("校验参数失败", ResponseBean.ERROR_ILLEGAL_PARAMS);
        }

        // 手机号解码
        String sessionKey = params.getString("sessionKey");
        String encryptedData = params.getString("encryptedData");
        String iv = params.getString("iv");

        // 楼盘ID
        String buildingId = params.getString("buildingId");
        // 场景ID
        String sceneId = params.getString("sceneId");
        // 访问目标
        String targetType = params.getString("targetType");
        // 目标ID
        String targetId = params.getString("targetId");
        // 目标名称
        String targetName = params.getString("targetName");
        // 推广用户 - 分享人
        String promoter = params.getString("recommender");
        // 置业顾问
        String consultantPersonId = request.getHeader("x-consultant");
        // 渠道ID
        String channelId = params.getString("channelId");
        // 推广码ID
        String qrCodeId = params.getString("qrCodeId");

        // 解密
        WxMaPhoneNumberInfo phoneNoInfo = miniAppService.getPhoneNoInfo(sessionKey, encryptedData, iv, appid);
        if (null == phoneNoInfo || StringUtils.isEmpty(phoneNoInfo.getPhoneNumber())) {
            ResponseBean.error("解析用户手机号码出错", ResponseBean.ERROR_UNAVAILABLE);
        }

        String openid = getOpenId(request);
        Integer orgId = getOrgId(request);
        String phone = phoneNoInfo.getPhoneNumber();

        TaCustomerFrom customerFrom = new TaCustomerFrom();
        customerFrom.setTargetType(targetType);
        customerFrom.setTargetId(targetId);
        customerFrom.setTargetName(targetName);
        customerFrom.setOrgId(orgId);
        customerFrom.setSceneId(sceneId);
        if (!StringUtils.isEmpty(channelId)) {
            customerFrom.setChannelId(Integer.valueOf(channelId));
        }
        if (!StringUtils.isEmpty(qrCodeId)) {
            customerFrom.setQrCodeId(Integer.valueOf(qrCodeId));
        }

        try {
            taPersonService.authPhone(
                    orgId,
                    openid,
                    phone,
                    buildingId,
                    promoter,
                    consultantPersonId,
                    customerFrom);

            return ResponseBean.success(phoneNoInfo);
        } catch (Exception e) {
           e.printStackTrace();
            return ResponseBean.error("授权手机失败: " + e.getMessage(), ResponseBean.ERROR_UNAVAILABLE);
        }
    }

    /**
     * 生成二维码
     *
     * @return
     */
    @PostMapping("/qrcode")
    public ResponseBean qrcode(@RequestBody String paramsStr, HttpServletRequest request) {
        String appid = request.getHeader("appid");
        return miniAppService.getQrCode(paramsStr, appid);
    }

    /**
     * 获取二维码参数
     *
     * @param serialNo
     * @return
     */
    @GetMapping("/qrcode/scene/{serialNo}")
    public ResponseBean getScene(@PathVariable String serialNo) {
        try {
            Integer id = Integer.valueOf(serialNo);
            TaMiniappQrcode qrcode = miniAppService.getQrCodeBySerialNo(id);
            if (null == qrcode) {
                return ResponseBean.error("不存在的二维码参数", HttpStatus.SC_BAD_REQUEST);
            }

            return ResponseBean.success(qrcode.getQrParams());
        } catch (Exception e) {
            e.printStackTrace();
            return ResponseBean.error("获取二维码参数失败: " + e.getMessage(), HttpStatus.SC_INTERNAL_SERVER_ERROR);
        }
    }

    public Integer getOrgId(HttpServletRequest request) {

        Map map = JWTUtils.getUserIdAndOrgId(request);
        if (null != map && null != map.get("orgId")) {
            return Integer.valueOf(map.get("orgId").toString());
        }

        return null;
    }
}
