package com.gree.mall.manager.logic.common;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.gree.mall.manager.bean.admin.AdminUserCom;
import com.gree.mall.manager.commonmapper.AdminMapper;
import com.gree.mall.manager.constant.Constant;
import com.gree.mall.manager.enums.RedisPrefixEnum;
import com.gree.mall.manager.exception.RemoteServiceException;
import com.gree.mall.manager.plus.entity.*;
import com.gree.mall.manager.plus.service.*;
import com.gree.mall.manager.utils.ApplicationContextUtils;
import com.gree.mall.manager.utils.CommonUtils;
import com.gree.mall.manager.utils.HttpUtils;
import com.gree.mall.manager.utils.RedisUtil;
import com.gree.mall.manager.utils.oss.OSSUtil;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import org.apache.commons.lang.time.DateUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class CommonLogic {

    @Value("${spring.profiles.active}")
    private String active;
    @Value("${wechat.payment.notifyUrl}")
    private String notifyUrl;
    @Value("${inf.url}")
    private String infUrl;
    @Value("${inf.token.appid}")
    private String clientId;
    @Value("${inf.token.appSecret}")
    private String clientSecret;
    //    @Value("${wechat.payment.refundNotifyUrl}")
//    private String refundNotifyUrl;
//    @Value("${wechat.keyPath}")
//    private String keyPath;

    @Autowired
    WechatLogic wechatLogic;
    @Autowired
    RedisUtil redisUtil;
    @Autowired
    AdminCompanyWechatService AdminCompanyWechatService;
    @Autowired
    CommonFileService commonFileService;
    @Autowired
    OrderInfoService orderInfoService;
    @Autowired
    RegionService regionService;
    @Autowired
    AdminUserService adminUserService;
    @Autowired
    AdminCompanyWechatService adminCompanyWechatService;
    @Autowired
    AdminUserWebsitRelaService adminUserWebsitRelaService;
    @Autowired
    AdminMapper adminMapper;
    @Autowired
    AdminWebsitService adminWebsitService;
    @Autowired
    UserService userService;
    @Autowired
    OSSUtil ossUtil;

    @Autowired
    AdminDeptService adminDeptService;

    @Autowired
    AdminUserDeptRelaService adminUserDeptRelaService;

    @Autowired
    AdminDeptWebsitService adminDeptWebsitService;

    public Map<String, String> getOSSConfig() throws UnsupportedEncodingException {
        return ossUtil.getConfig();
    }

    public AdminUserCom getAdminUser(){
        HttpServletRequest request = ApplicationContextUtils.getHttpServletRequest();
        return this.getAdminUser(request);
    }

    /**
     * 获取帐号以及部门id集合
     */
    public AdminUserCom getAdminUser(HttpServletRequest request){
        String userId = CommonUtils.getUserId(request);
        String token = CommonUtils.getToken(request);
        return this.getAdminUser(userId,token);
    }


    public AdminUserCom getAdminUser(String userId, String token){

        //方便测试用
        if(userId == null && !active.equals("prd")){
            AdminUser admin = adminUserService.lambdaQuery().eq(AdminUser::getUserName, "admin").one();
            AdminUserCom adminUserCom = new AdminUserCom();
            BeanUtils.copyProperties(admin,adminUserCom);
            AdminCompanyWechat adminCompanyWechat = adminCompanyWechatService.getById("1831608878894858241");
            adminUserCom.setAdminCompanyWechat(adminCompanyWechat);
            adminUserCom.setJoinCode(adminCompanyWechat.getJoinCode());

            List<AdminUserDeptRela> adminUserDeptRelas = adminUserDeptRelaService.lambdaQuery().in(AdminUserDeptRela::getAdminUserId, admin.getAdminUserId()).list();
            if (!CollectionUtils.isEmpty(adminUserDeptRelas)) {
                List<String> deptIds = adminUserDeptRelas.stream().map(AdminUserDeptRela::getAdminDeptId).collect(Collectors.toList());
                adminUserCom.setAdminDept(adminDeptService.lambdaQuery().in(AdminDept::getAdminDeptId,deptIds).list());
            }

            return adminUserCom;
        }
        String redisKey = RedisPrefixEnum.TOKEN_MGR.toString() + token;
        AdminUserCom adminUserCom = (AdminUserCom)redisUtil.get(redisKey);
        if(adminUserCom != null) {
            return adminUserCom;
        }

        AdminUser adminUser = adminUserService.getById(userId);
        if(adminUser == null){
            return null;
        }
        if(!adminUser.getStatus()){
            throw new RemoteServiceException("帐号已被禁用");
        }
        adminUserCom = new AdminUserCom();
        BeanUtils.copyProperties(adminUser,adminUserCom);



        //商品出入库是否关联条码\
        AdminCompanyWechat adminCompanyWechat = adminCompanyWechatService.getById(adminUser.getCompanyWechatId());
        if(adminCompanyWechat != null){
            adminUserCom.setJoinCode(adminCompanyWechat.getJoinCode());
        }

        List<AdminUserDeptRela> adminUserDeptRelaList = adminUserDeptRelaService.lambdaQuery()
                .eq(AdminUserDeptRela::getAdminUserId, adminUser.getAdminUserId()).list();


        //所有帐号
       // adminUserCom = this.websitAccount(adminUserCom);

        List<AdminUserWebsitRela> websitList = adminUserWebsitRelaService.lambdaQuery().eq(AdminUserWebsitRela::getAdminUserId, userId).list();
        if(!CollectionUtils.isEmpty(websitList)){
            List<String> adminWebsitIds = websitList.stream().map(AdminUserWebsitRela::getAdminWebsitId).distinct().collect(Collectors.toList());
            List<String> companyWechatIds = websitList.stream().map(AdminUserWebsitRela::getCompanyWechatId).distinct().collect(Collectors.toList());

            List<AdminWebsit> list = new ArrayList<>();
            for(String websitId : adminWebsitIds) {
                list.addAll(this.queryAllChild(list, websitId));
            }
            List<String> websitIds = list.stream().map(AdminWebsit::getWebsitId).distinct().collect(Collectors.toList());
            websitIds.addAll(adminWebsitIds);


            AdminWebsit adminWebsit = adminWebsitService.getById(websitList.get(0).getAdminWebsitId());
            adminUserCom.setCompanyWechatIds(companyWechatIds);
            adminUserCom.setAdminWebsitIds(websitIds.stream().distinct().collect(Collectors.toList()));
            adminUserCom.setOnlyRead(companyWechatIds.size() > 1);


            List<AdminWebsit> adminWebsitList = adminWebsitService.lambdaQuery().in(AdminWebsit::getWebsitId, websitList.get(0).getAdminWebsitId()).list();
            adminUserCom.setAdminWebsit(adminWebsitList);
            //获取当前登录人的企业微信配置
            AdminCompanyWechat adminCompanyWechatA = this.getAdminCompanyWechat(companyWechatIds.get(0));
            adminUserCom.setAdminCompanyWechat(adminCompanyWechatA);
        }


        if (!CollectionUtils.isEmpty(adminUserDeptRelaList)){

            List<String> deptids = adminUserDeptRelaList.stream().map(AdminUserDeptRela::getAdminDeptId).collect(Collectors.toList());
            List<AdminDept> adminDepts = adminDeptService.lambdaQuery().in(AdminDept::getAdminDeptId, deptids).list();
            adminUserCom.setAdminDept(adminDepts);
            List<AdminDeptWebsit> adminDeptWebsitList = adminDeptWebsitService.lambdaQuery()
                    .in(AdminDeptWebsit::getAdminDeptId, deptids).list();
            List<String> collect = adminDeptWebsitList.stream().map(AdminDeptWebsit::getWebsitId).collect(Collectors.toList());
            if (!CollectionUtils.isEmpty(adminUserCom.getAdminWebsitIds())) {
                adminUserCom.getAdminWebsitIds().addAll(collect);

            }else {
                adminUserCom.setAdminWebsitIds(collect);
            }

            List<String> ids = new ArrayList<>();
            if (adminCompanyWechat != null) {
                ids.add(adminCompanyWechat.getCompanyWechatId());
                adminUserCom.setCompanyWechatIds(ids);
                adminUserCom.setAdminCompanyWechat(adminCompanyWechat);
            }
        }



        return adminUserCom;
    }

    /**
     * 部门帐号
     */
    public AdminUserCom websitAccount(AdminUserCom adminUserCom){
        String userId = adminUserCom.getAdminUserId();
        //非平台账号
        if(adminUserCom.getType() != 2){
            List<AdminUserWebsitRela> websitList = adminUserWebsitRelaService.lambdaQuery().eq(AdminUserWebsitRela::getAdminUserId, userId).list();
            if(CollectionUtils.isEmpty(websitList)){
                return adminUserCom;
            }

            List<String> adminWebsitIds = websitList.stream().map(AdminUserWebsitRela::getAdminWebsitId).distinct().collect(Collectors.toList());
            List<String> companyWechatIds = websitList.stream().map(AdminUserWebsitRela::getCompanyWechatId).distinct().collect(Collectors.toList());


            List<AdminWebsit> list = new ArrayList<>();
            for(String websitId : adminWebsitIds) {
                list.addAll(this.queryAllChild(list, websitId));
            }
            List<String> websitIds = list.stream().map(AdminWebsit::getWebsitId).distinct().collect(Collectors.toList());
            websitIds.addAll(adminWebsitIds);


            AdminWebsit adminWebsit = adminWebsitService.getById(websitList.get(0).getAdminWebsitId());
            adminUserCom.setCompanyWechatIds(companyWechatIds);
            adminUserCom.setAdminWebsitIds(websitIds.stream().distinct().collect(Collectors.toList()));
            adminUserCom.setOnlyRead(companyWechatIds.size() > 1);
           // adminUserCom.setAdminWebsit(adminWebsit);
            //获取当前登录人的企业微信配置
            AdminCompanyWechat adminCompanyWechat = this.getAdminCompanyWechat(companyWechatIds.get(0));
            adminUserCom.setAdminCompanyWechat(adminCompanyWechat);
        }
        return adminUserCom;
    }

    /**
     * 获取企业微信配置
     */
    public AdminCompanyWechat getAdminCompanyWechat(String companyWechatId){
        AdminCompanyWechat adminCompanyWechat = adminCompanyWechatService.getById(companyWechatId);
        return adminCompanyWechat;
    }
    /**
     * 获取所有企业微信配置
     */
    public List<AdminCompanyWechat> getAdminCompanyList(){
        List<AdminCompanyWechat> list = adminCompanyWechatService.list();
        return list;
    }


    /**
     * 递归查询所有数据
     */
    public List<AdminWebsit> queryAllChild(List<AdminWebsit> list,String id){
        if(id == null || id.equals("0")){
            return list;
        }
        List<AdminWebsit> adminWebsits = adminWebsitService.lambdaQuery().eq(AdminWebsit::getParentId, id).list();
        if(adminWebsits.size() == 0){
            return list;
        }
        for(AdminWebsit adminWebsit:adminWebsits){
            this.queryAllChild(list,adminWebsit.getWebsitId());
        }
        list.addAll(adminWebsits);
        return list;
    }

    /**
     * 刷新微信相关配置
     */
    public void reloadWxConfig(){
//        List<AdminCompanyWechat> list = AdminCompanyWechatService.list();
//        log.info("【刷新微信配置开始】");
//        WxConfiguration.reloadWxConfig(list,redisUtil,keyPath,notifyUrl);
//        log.info("【刷新微信配置成功】");
    }

    /**
     * 附件归属绑定
     */
    public void bindFile(String objId,String objType,List<String> fileIds){
        //先删除后绑定
        commonFileService.lambdaUpdate()
                .eq(CommonFile::getObjId,objId)
                .eq(CommonFile::getObjType,objType)
                .notIn(CommonFile::getId,fileIds).remove();

        for(int i =0;i< fileIds.size();i++) {
            //这里分开每次存储的时候，每个图片创建时间加1秒，方便图片排序用
            commonFileService.lambdaUpdate()
                    .set(CommonFile::getObjId, objId)
                    .set(CommonFile::getObjType, objType)
                    .set(CommonFile::getCreateTime,DateUtils.addSeconds(new Date(),i))
                    .eq(CommonFile::getId, fileIds.get(i))
                    .update();
        }
    }
    /**
     * 附件归属绑定
     */
    public void bindFileFile(String objId,String objType,List<CommonFile> fileIds){
        if(org.apache.commons.collections4.CollectionUtils.isEmpty(fileIds)){
            return;
        }
        //先删除后绑定
        commonFileService.lambdaUpdate()
                .eq(CommonFile::getObjId,objId)
                .eq(CommonFile::getObjType,objType).remove();

        for(CommonFile file : fileIds) {
            file.setId(null);
            file.setObjId(objId);
            file.setObjType(objType);
        }
        commonFileService.saveBatch(fileIds);
    }

    /**
     * 查询附件列表
     */
    public List<CommonFile> queryFileByObjId(String objId,String objType){
        return commonFileService.lambdaQuery()
                .eq(CommonFile::getObjId,objId)
                .eq(CommonFile::getObjType,objType)
                .orderByAsc(CommonFile::getCreateTime)
                .list();
    }

    /**
     * 查询附件列表
     */
    public List<String> queryFileUrlsByObjId(String objId,String objType){
        List<CommonFile> commonFiles = this.queryFileByObjId(objId, objType);
        if(commonFiles.size() == 0){
            return null;
        }
        return commonFiles.stream().map(CommonFile::getUrl).collect(Collectors.toList());
    }


    /**
     * 上传附件
     * @param file
     * @return
     * @throws IOException
     */
    public CommonFile uploadFile( MultipartFile file) throws IOException, RemoteServiceException {

        if (file == null || file.isEmpty()) {
            return null;
        }
        String uploadFilePath = file.getOriginalFilename().replaceAll("\\\\", "/");
        String uploadFileName = uploadFilePath.substring(
                uploadFilePath.lastIndexOf('/') + 1, uploadFilePath.lastIndexOf('.'));
        String uploadFileSuffix = uploadFilePath.substring(uploadFilePath.lastIndexOf('.') + 1, uploadFilePath.length());
        long currentTime = System.currentTimeMillis();
        BufferedOutputStream bufferedOutputStream = null;

        //限制大小为10m
        if (file.getSize() > 1024 * 1024 * 30) {
            throw new RemoteServiceException("文件大小超出限制");
        }

        try {
            String filePath = ossUtil.getFilePath() + "/" + currentTime + UUID.randomUUID().toString() + "." + uploadFileSuffix;
            if (!ossUtil.uploadFile(filePath, file.getBytes())) {
                throw new RemoteServiceException("文件同步oss失败");
            }
            String ossUrl = ossUtil.getAccessUrl() + filePath;

            CommonFile commonFile = new CommonFile();
            commonFile.setUrl(ossUrl);
            commonFile.setName(uploadFileName);
            commonFile.setFileType(uploadFileSuffix);
            commonFile.setFileSize(BigDecimal.valueOf(file.getSize()));
            commonFile.setCreateTime(new Date());
            commonFileService.save(commonFile);
            return commonFile;
        } finally {
            if (bufferedOutputStream != null) {
                bufferedOutputStream.close();
            }
        }
    }


    public List<Region> queryRegionList(String pid){
        return regionService.lambdaQuery().eq(Region::getPid,pid).list();
    }

    public String getFile(String key) throws IOException {
        String url = ossUtil.getUrlWw(key);
        return url;
    }



    /**
     * 生成订单号
     * @param start 前缀
     * @param orderType 订单类型
     * @param length 一般13 位
     * @return
     */
    public String generateNo(String start, String orderType, int length) {
        String dayFmt = DateUtil.format(new Date(), "yyMMdd");
        String tNumKey = Constant.RedisPrefix.ORDER_NUM + orderType + dayFmt;
        StringBuffer number = new StringBuffer();
        number.append(start);
        number.append(dayFmt);
        int ramainLen = length - number.toString().length();
        //自增 填充位数
        Object value = redisUtil.incr(tNumKey, 1);
        redisUtil.expire(tNumKey, 24 * 60 * 60);
        number.append(String.format("%0" + ramainLen + "d", Integer.parseInt(value.toString())));
        return number.toString();
    }

    public String generateReqNo(String start, String orderType, int length) {
        String dayFmt = DateUtil.format(new Date(), "yyyyMMdd");
        String tNumKey = Constant.RedisPrefix.ORDER_NUM + orderType + dayFmt;
        StringBuffer number = new StringBuffer();
        number.append(start);
        // number.append(dayFmt);
        int ramainLen = length - number.toString().length();
        //自增 填充位数
        Object value = redisUtil.incr(tNumKey, 1);
        redisUtil.expire(tNumKey, 24 * 60 * 60);
        number.append(String.format("%0" + ramainLen + "d", Integer.parseInt(value.toString())));
        return number.toString();
    }

    /**
     * 生成辅材编号
     * @param companyId 商户编号
     * @param start 前缀
     * @param orderType 订单类型
     * @param length 一般13 位
     * @return
     */
    public String generateMaterialNo(String companyId, String start, String orderType, int length) {
        String dayFmt = DateUtil.format(new Date(), "yyyyMMdd");
        String tNumKey = Constant.RedisPrefix.ORDER_NUM + dayFmt + orderType + companyId;
        StringBuilder number = new StringBuilder();
        number.append(start);
        number.append(dayFmt);
        int ramainLen = length - number.toString().length();
        //自增 填充位数
        Object value = redisUtil.incr(tNumKey, 1);
        redisUtil.expire(tNumKey, 24 * 60 * 60);
        number.append(String.format("%0" + ramainLen + "d", Integer.parseInt(value.toString())));
        return number.toString();
    }


    /**
     * 获取跳往小程序的链接（带公众号openid）
     * @param code
     * @param pubAppId
     * @return
     * @throws WxErrorException
     */
//    public String getPubOpenIdUrl(String code,String pubAppId) throws WxErrorException, IOException {
//        AdminCompanyWechat adminCompanyWechat = adminCompanyWechatService.lambdaQuery().eq(AdminCompanyWechat::getPubAppId, pubAppId).last("limit 1").one();
//        if(adminCompanyWechat == null){
//            throw new RemoteServiceException("缺少配置，请联系相关人员");
//        }
//        String mpOpenId = wechatLogic.pubAuthOpenId(code, adminCompanyWechat);
//        Integer count = userService.lambdaQuery().eq(User::getMpOpenId, mpOpenId).count();
//        if(count > 0){
//            return "";
//        }
//        String urlScheme = wechatLogic.getUrlScheme("mpOpenId="+mpOpenId, adminCompanyWechat.getCompanyWechatId());
//        return urlScheme;
//    }

    /**
     * 获取公众号openid
     * @param code
     * @param pubAppId
     * @return
     * @throws WxErrorException
     */
    public String getPubOpenId(String code,String pubAppId) throws WxErrorException, IOException {
        AdminCompanyWechat adminCompanyWechat = adminCompanyWechatService.lambdaQuery().eq(AdminCompanyWechat::getPubAppId, pubAppId).last("limit 1").one();
        if(adminCompanyWechat == null){
            throw new RemoteServiceException("缺少配置，请联系相关人员");
        }
        String mpOpenId = wechatLogic.pubAuthOpenId(code, adminCompanyWechat);
        return mpOpenId;
    }

    public InputStream getFileInputStreamByUrl(String strUrl) {
        try {
            log.info("【附件路径】:{}",strUrl);
            URL url = new URL(strUrl);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");
            conn.setConnectTimeout(60 * 1000);
            InputStream inStream = conn.getInputStream();// 通过输入流获取图片数据
            return inStream;
        } catch (Exception e) {
            log.error("生成附件失败"+e.getMessage());
        }
        return null;
    }

    public String getInfToken() throws RemoteServiceException {
        Object token = redisUtil.get(Constant.RedisPrefix.INF_TOKEN);

        if (token != null) {
            return token.toString();
        }
        //过期就重新获取
        return this.deleteAndAddInfToken();
    }

    public String deleteAndAddInfToken() throws RemoteServiceException {
        HashMap<String, String> params = new HashMap();
        params.put("clientId", this.clientId);
        params.put("clientSecret", this.clientSecret);
        String content = HttpUtils.requestGet(this.infUrl + "/com/token/get", params, null);
        Map<String, Object> resMap = JSON.parseObject(content, new TypeReference<HashMap<String, Object>>() {
        });

        int code = (int) resMap.get("code");
        if (code == 1) {
            String token = (String) resMap.get("data");
            redisUtil.set(Constant.RedisPrefix.INF_TOKEN, token, (2 * 60 * 60) - 30);//2小时过期
            return token;
        }
        return null;
    }

    public String getInfUrl() {
        return infUrl;
    }

    /**
     * 后台计算值
     * @param frontVal
     * @param afterVal
     * @param operator
     * @param scale
     * @param roundingMode
     * @return
     */
    public BigDecimal computeVal(BigDecimal frontVal, BigDecimal afterVal, String operator, Integer scale, Integer roundingMode) {
        frontVal = Optional.ofNullable(frontVal).orElse(BigDecimal.ZERO);
        afterVal = Optional.ofNullable(afterVal).orElse(BigDecimal.ZERO);
        operator = Optional.ofNullable(operator).orElse("+");
        scale = Optional.ofNullable(scale).orElse(2);
        switch (operator) {
            case "+":
                return frontVal.add(afterVal).setScale(scale, roundingMode);
            case "-":
                return frontVal.subtract(afterVal).setScale(scale, roundingMode);
            case "*":
                return frontVal.multiply(afterVal).setScale(scale, roundingMode);
            case "/":
                return frontVal.divide(afterVal, scale, roundingMode);
            default:
                return BigDecimal.ZERO;
        }
    }
}
