package com.fjhx.jushuitan.service.api;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.SerializeUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.parser.ParserConfig;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.PropertyNamingStrategy;
import com.fjhx.jushuitan.constants.JstConstant;
import com.fjhx.jushuitan.entity.jst.dto.JstOrderDetailDto;
import com.fjhx.jushuitan.entity.jst.po.JstOrderDetail;
import com.fjhx.jushuitan.entity.jst.po.JstOrderInfo;
import com.fjhx.jushuitan.entity.jst.po.JstOrderPayInfo;
import com.fjhx.jushuitan.entity.jst.vo.JstOrderDetailVo;
import com.fjhx.jushuitan.entity.jst.vo.JstOrderInfoVo;
import com.fjhx.jushuitan.entity.jst.vo.JstOrderPayInfoVo;
import com.fjhx.jushuitan.entity.jushuitan.po.JushuitanConfig;
import com.fjhx.jushuitan.entity.jushuitan.vo.JstApiOrderInfoVO;
import com.fjhx.jushuitan.entity.jushuitan.vo.RefreshTokenResponseVO;
import com.fjhx.jushuitan.service.jst.JstOrderDetailService;
import com.fjhx.jushuitan.service.jst.JstOrderInfoService;
import com.fjhx.jushuitan.service.jst.JstOrderPayInfoService;
import com.fjhx.jushuitan.service.jushuitan.JushuitanConfigService;
import com.jushuitan.api.*;
import com.jushuitan.api.exception.ApiException;
import com.jushuitan.api.util.AuthUtil;
import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.system.service.ISysDeptService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.logging.Logger;
import java.util.stream.Collectors;

@Service
@Slf4j
public class JstApiService {
    @Resource
    JushuitanConfigService jstConfigService;
    @Resource
    JstOrderInfoService jstOrderInfoService;
    @Resource
    JstOrderDetailService jstOrderDetailService;
    @Resource
    JstOrderPayInfoService jstOrderPayInfoService;
    @Resource
    ISysDeptService sysDeptService;

    /**
     * 刷新token(每天凌晨1点刷新)
     */
    @Scheduled(cron = "0 0 1  * * ? ")
    public void refreshToken() {
        SecurityUtils.setTenantId(JstConstant.TENANT_ID);
        List<JushuitanConfig> list = jstConfigService.list();
        for (JushuitanConfig jushuitanConfig : list) {
            if(StrUtil.isBlank(jushuitanConfig.getRefreshToken())){
                log.error("刷新token失败，refreshToken为空，jushuitanConfig:{}",JSON.toJSONString(jushuitanConfig));
                continue;
            }
            //如果有效期时间小于15天，刷新token
            Date effectiveDate = jushuitanConfig.getEffectiveDate();
            if(ObjectUtil.isNull(effectiveDate) || DateUtil.betweenDay(effectiveDate, DateUtil.date(), true) < 15){
                // 设置超时时间
                AuthRequest authRequest = new AuthRequest.Builder(jushuitanConfig.getAppKey(), jushuitanConfig.getAppSecret()).refreshToken(jushuitanConfig.getRefreshToken()).build();
                try {
                    String s = AuthUtil.refreshToken(authRequest);
                    RefreshTokenResponseVO refreshTokenResponseVO = JSONObject.parseObject(s, RefreshTokenResponseVO.class);
                    if (JstConstant.SUCCESS_CODE.equals(refreshTokenResponseVO.getCode())) {
                        RefreshTokenResponseVO.ResponseData data = refreshTokenResponseVO.getData();
                        jushuitanConfig.setAccessToken(data.getAccessToken());
                        jushuitanConfig.setRefreshToken(data.getRefreshToken());
                        jushuitanConfig.setEffectiveDate(DateUtil.offsetSecond(DateUtil.date(), NumberUtil.parseInt(StrUtil.toString(data.getExpiresIn()))));
                        jstConfigService.updateById(jushuitanConfig);
                    } else {
                        log.error("刷新token失败，jushuitanConfig:{},refreshTokenResponseVO:{}", JSON.toJSONString(jushuitanConfig), JSON.toJSONString(refreshTokenResponseVO));
                    }
                    System.out.println("body: " + s);
                } catch (ApiException e) {
                    switch (e.getCodeEnum()) {
                        case PARAM_ERROR:
                            // TODO check param
                            log.error("参数错误，jushuitanConfig:{}", JSON.toJSONString(jushuitanConfig));
                            break;
                    }
                } catch (IOException e) {
                    log.error("IO异常，jushuitanConfig:{}", JSON.toJSONString(jushuitanConfig));
                }
            }
        }
        SecurityUtils.clearTenantId();
    }

    public void getOrder(JushuitanConfig jushuitanConfig) {
        int pageIndex = JstConstant.PAGE_INDEX;
        int totalPage;
        JSONObject bizJson = new JSONObject();
        //查询库里数据，获取最后一次ts
        Long lastTs = jstOrderInfoService.getLastTs();
        try {
            do{
                if (ObjectUtil.isNull(lastTs)) {
                    bizJson.put("modified_begin", DateUtil.beginOfDay(DateUtil.offsetDay(DateUtil.date(), -6)).toString(DatePattern.NORM_DATETIME_PATTERN));
                    bizJson.put("modified_end", DateUtil.endOfDay(DateUtil.date()).toString(DatePattern.NORM_DATETIME_PATTERN));
                    bizJson.put("page_size", JstConstant.PAGE_SIZE);
                    bizJson.put("page_index", pageIndex);
                }else {
                    bizJson.put("page_size", JstConstant.PAGE_SIZE);
                    bizJson.put("start_ts", lastTs);
                }
                String body = executeJst(bizJson);
                ParserConfig specialConfig = new ParserConfig();
                specialConfig.propertyNamingStrategy = PropertyNamingStrategy.SnakeCase;
                JstApiOrderInfoVO jstApiOrderInfoVO = JSONObject.parseObject(body, JstApiOrderInfoVO.class, specialConfig);
                JstApiOrderInfoVO.ResponseData data = jstApiOrderInfoVO.getData();
                if (ObjectUtil.isNull(data)) {
                    log.error("获取订单失败，jushuitanConfig:{},jstApiOrderInfoVO:{}", JSON.toJSONString(jushuitanConfig), JSON.toJSONString(jstApiOrderInfoVO));
                    throw new ApiException(ApiCodeEnum.SYS_ERROR);
                }
                totalPage = data.getPageCount();
                handleDbData(data.getOrders());
                //获取最后一条的ts
                lastTs = data.getOrders().get(data.getOrders().size() - 1).getTs();
                pageIndex++;
            } while (pageIndex <= totalPage);
        } catch (ApiException e) {
            switch (e.getCodeEnum()) {
                case SYS_ERROR:
                case PARAM_ERROR:
                case SIGN_ERROR:
                case CONNECT_ERROR:
                case TIME_OUT_ERROR:
                case EXECUTE_ERROR:
                    log.error("获取订单失败，jushuitanConfig:{}", JSON.toJSONString(jushuitanConfig), e);
                    break;
            }
        } catch (Exception e) {
            log.error("获取订" +
                    "单失败，jushuitanConfig:{}", JSON.toJSONString(jushuitanConfig), e);
        }
    }

    /**
     * 处理数据库数据
     * @param orders
     */
    @Transactional(rollbackFor = Exception.class)
    public void handleDbData(List<JstOrderInfoVo> orders) {
        for (JstOrderInfoVo order : orders) {
            //如果订单已存在，
            Long oid = order.getOid();
            List<JstOrderInfo> list = jstOrderInfoService.lambdaQuery().eq(JstOrderInfo::getOid, oid).list();
            if (CollectionUtil.isNotEmpty(list)) {
                jstOrderInfoService.lambdaUpdate().eq(JstOrderInfo::getOid, oid).remove();
                jstOrderDetailService.lambdaUpdate().eq(JstOrderDetail::getOrderId, oid).remove();
                jstOrderPayInfoService.lambdaUpdate().eq(JstOrderPayInfo::getOrderId, oid).remove();
            }

            String drpFrom = order.getDrpFrom();
            if(StrUtil.isNotBlank(drpFrom)){
                sysDeptService.lambdaQuery().eq(SysDept::getJstDistributor, drpFrom).oneOpt().ifPresent(o -> {
                    order.setDeptId(o.getDeptId());
                });
            }

            jstOrderInfoService.save(order);
            List<JstOrderDetailVo> items = order.getItems();
            List<JstOrderDetail> detailDtoList = items.stream().map(o -> {
                o.setOrderId(order.getId());
                JstOrderDetail jstOrderDetailDto = BeanUtil.toBean(o, JstOrderDetail.class);
                return jstOrderDetailDto;
            }).collect(Collectors.toList());
            jstOrderDetailService.saveBatch(detailDtoList);
            List<JstOrderPayInfoVo> pays = order.getPays();
            List<JstOrderPayInfo> payDtoList = pays.stream().map(o -> {
                o.setOrderId(order.getId());
                JstOrderPayInfo jstOrderPayInfoDto = BeanUtil.toBean(o, JstOrderPayInfo.class);
                return jstOrderPayInfoDto;
            }).collect(Collectors.toList());
            jstOrderPayInfoService.saveBatch(payDtoList);
        }
    }


    private String executeJst(JSONObject bizJson){
        // 实例化client
        ApiClient client = new DefaultApiClient();
        // 设置超时时间
        //        ((DefaultApiClient)client).setReadTimeout(3000);
        //        ((DefaultApiClient)client).setConnectTimeout(2000);

        String url = JstConstant.DOMAIN_URL+JstConstant.QUERY_ORDER;
        String biz = bizJson.toString();
        // 构建请求对象
        ApiRequest request = new ApiRequest.Builder(url, JstConstant.APP_KEY, JstConstant.APP_SECRET)
                .biz(biz).build();
        // 执行接口调用
        ApiResponse response = client.execute(request, JstConstant.ACCESS_TOKEN);
        if (!response.isSuccess()) {
            log.error("获取订单失败，response:{}", JSON.toJSONString(response));
            throw new ApiException(ApiCodeEnum.SYS_ERROR);
        }
        return response.getBody();
    }

    @Async
    public void startOrder() {
        ThreadUtil.safeSleep(JstConstant.SLEEP_ONE_MINUTE);
        while (true){
            SecurityUtils.setTenantId(JstConstant.TENANT_ID);
            List<JushuitanConfig> list = jstConfigService.list();
            for (JushuitanConfig jushuitanConfig : list) {
                if (StrUtil.isBlank(jushuitanConfig.getAccessToken()) || StrUtil.isBlank(jushuitanConfig.getAppKey()) || StrUtil.isBlank(jushuitanConfig.getAppSecret()) || DateUtil.between(DateUtil.date(), jushuitanConfig.getEffectiveDate(), DateUnit.DAY, false) < 0) {
                    log.error("获取订单失败，accessToken、appKey、appSecret为空、token有效期失效，jushuitanConfig:{}", JSON.toJSONString(jushuitanConfig));
                    ThreadUtil.safeSleep(JstConstant.SLEEP_ONE_MINUTE);
                    continue;
                }
                getOrder(jushuitanConfig);
                log.info("订单采集完成：appKey为：{}", jushuitanConfig.getAppKey());
                ThreadUtil.safeSleep(JstConstant.SLEEP_ONE_MINUTE);
            }
            SecurityUtils.clearTenantId();
        }
    }
}
