package com.gic.haoban.manage.service.service.out.impl.fee;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.gic.api.base.commons.Page;
import com.gic.commons.util.EntityUtil;
import com.gic.commons.util.GICMQClientUtil;
import com.gic.commons.util.UniqueIdUtils;
import com.gic.dubbo.entity.ProviderLocalTag;
import com.gic.haoban.common.utils.PageUtil;
import com.gic.haoban.manage.api.constants.Manage3Constants;
import com.gic.haoban.manage.api.dto.AlertMessageDTO;
import com.gic.haoban.manage.api.dto.WxEnterpriseDTO;
import com.gic.haoban.manage.api.dto.WxEnterpriseQwDTO;
import com.gic.haoban.manage.api.dto.fee.HaobanQywxFeeAccountInterceptLogDTO;
import com.gic.haoban.manage.api.dto.fee.HaobanQywxFeeDTO;
import com.gic.haoban.manage.api.dto.fee.HaobanQywxFeeDetailDTO;
import com.gic.haoban.manage.api.dto.qdto.QywxFeeListQDTO;
import com.gic.haoban.manage.api.enums.AlertTypeEnum;
import com.gic.haoban.manage.api.service.fee.HaobanQywxFeeApiService;
import com.gic.haoban.manage.service.config.Config;
import com.gic.haoban.manage.service.entity.TabHaobanStaff;
import com.gic.haoban.manage.service.entity.TabHaobanWxEnterprise;
import com.gic.haoban.manage.service.entity.fee.TabHaobanQywxFee;
import com.gic.haoban.manage.service.entity.fee.TabHaobanQywxFeeAccountInterceptLog;
import com.gic.haoban.manage.service.entity.fee.TabHaobanQywxFeeOrder;
import com.gic.haoban.manage.service.entity.fee.TabHaobanQywxFeeOrderAccount;
import com.gic.haoban.manage.service.pojo.bo.fee.HaobanQywxFeeBO;
import com.gic.haoban.manage.service.service.StaffService;
import com.gic.haoban.manage.service.service.WxEnterpriseActiveDataService;
import com.gic.haoban.manage.service.service.WxEnterpriseService;
import com.gic.haoban.manage.service.service.fee.HaobanQywxFeeAccountInterceptLogService;
import com.gic.haoban.manage.service.service.fee.HaobanQywxFeeAccountStaffService;
import com.gic.haoban.manage.service.service.fee.HaobanQywxFeeOrderAccountService;
import com.gic.haoban.manage.service.service.fee.HaobanQywxFeeOrderService;
import com.gic.haoban.manage.service.service.fee.HaobanQywxFeeService;
import com.gic.mq.sdk.GicMQClient;
import com.gic.redis.data.util.RedisUtil;
import com.gic.wechat.api.dto.qywx.fee.AccountListDTO;
import com.gic.wechat.api.dto.qywx.fee.AccountListResponseDTO;
import com.gic.wechat.api.dto.qywx.fee.ActiveInfoCodeResponseDTO;
import com.gic.wechat.api.dto.qywx.fee.FeeOrderDeatilResponseDTO;
import com.gic.wechat.api.dto.qywx.fee.FeeOrderResponseList;
import com.gic.wechat.api.dto.qywx.fee.qdto.FeeOrderListQDTO;
import com.gic.wechat.api.service.qywx.QywxUserApiService;
import com.google.common.collect.Lists;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUtil;

@Service("haobanQywxFeeApiService")
public class HaobanQywxFeeApiServiceImpl implements HaobanQywxFeeApiService {

    private static Logger logger = LoggerFactory.getLogger(HaobanQywxFeeApiServiceImpl.class);

    @Autowired
    private HaobanQywxFeeService haobanQywxFeeService;
    @Autowired
    private HaobanQywxFeeOrderService haobanQywxFeeOrderService;
    @Autowired
    private HaobanQywxFeeOrderAccountService haobanQywxFeeOrderAccountService;
    @Autowired
    private HaobanQywxFeeAccountStaffService haobanQywxFeeAccountStaffService;
    @Autowired
    private QywxUserApiService qywxUserApiService;
    @Autowired
    private Config config;
    @Autowired
    private WxEnterpriseService wxEnterpriseService;
    @Autowired
    private StaffService staffService;
    @Autowired
    private HaobanQywxFeeAccountInterceptLogService haobanQywxFeeAccountInterceptLogService;
    @Autowired
    private WxEnterpriseActiveDataService wxEnterpriseActiveDataService;

    @Override
    public void run(String param) {
        List<TabHaobanWxEnterprise> tabHaobanWxEnterprises = wxEnterpriseService.listAll();
        for (TabHaobanWxEnterprise wxEnterprise : tabHaobanWxEnterprises) {
            GicMQClient instance = GICMQClientUtil.getClientInstance();
            try {
                instance.sendMessage("qywxAddFeeMq", wxEnterprise.getWxEnterpriseId());
            } catch (Exception e) {
                logger.info("发送消息处理异常：{}", e.getMessage(), e);
            }
        }
    }

    private List<String> listOrderId(String corpid) {
        List<String> orderIds = new ArrayList<>();
        FeeOrderListQDTO feeOrderListQDTO = new FeeOrderListQDTO();
        feeOrderListQDTO.setCorpid(corpid);
        if (null == RedisUtil.getCache("qywx-order-search-date")) {
            feeOrderListQDTO
                    .setStartTime(DateUtil.beginOfDay(new Date()).offsetNew(DateField.HOUR_OF_DAY, -24).getTime());
            feeOrderListQDTO.setEndTime(new Date().getTime());
        }
        feeOrderListQDTO.setLimit(Manage3Constants.QW_LIMIT);
        FeeOrderResponseList feeOrderResponseList = qywxUserApiService.listOrder(corpid, config.getCorpid(),
                feeOrderListQDTO);
        logger.error("查询激活码订单,{}", JSON.toJSONString(feeOrderResponseList));
        int errcode = feeOrderResponseList.getErrcode();
        if (errcode == 0) {
            for (FeeOrderResponseList.OrderListDTO orderListDTO : feeOrderResponseList.getOrderList()) {
                orderIds.add(orderListDTO.getOrderId());
            }
        }
        return orderIds;
    }

    // 查询订单下的激活码code列表
    private void getOrderAccount(String orderId, String corpid, String cursor,
            List<Map<String, String>> activeCodeList) {
        logger.info("处理订单激活码,orderid={}", orderId);
        FeeOrderListQDTO feeOrderListQDTO = new FeeOrderListQDTO();
        feeOrderListQDTO.setOrderId(orderId);
        feeOrderListQDTO.setCursor(cursor);
        feeOrderListQDTO.setLimit(Manage3Constants.QW_LIMIT);
        AccountListResponseDTO accountListResponseDTO = qywxUserApiService.listOrderAccount(corpid, config.getCorpid(),
                feeOrderListQDTO);
        if (accountListResponseDTO.getErrcode() != 0) {
            logger.info("订单账号列表报错：{}", accountListResponseDTO.getErrmsg());
            return;
        }
        // 只记录互通账号
        for (AccountListDTO accountListDTO : accountListResponseDTO.getAccountList()) {
            if (accountListDTO.getType() == 2) {
                Map<String, String> map = new HashMap<>();
                map.put("orderId", orderId);
                map.put("activeCode", accountListDTO.getActiveCode());
                activeCodeList.add(map);
            }
        }
        cursor = accountListResponseDTO.getNextCursor();
        Integer hasMore = accountListResponseDTO.getHasMore();
        if (hasMore == 1 && StringUtils.isNotBlank(cursor)) {
            this.getOrderAccount(orderId, corpid, cursor, activeCodeList);
        }
    }

    @Override
    public void addFee(String wxEnterpriseId) {
        logger.info("企微收费wxEnterpriseId={}", wxEnterpriseId);
        if (StringUtils.isBlank(wxEnterpriseId)) {
            logger.info("wxEnterpriseId为空");
            return;
        }
        String serviceCorpid = config.getCorpid();
        WxEnterpriseDTO wxEnterpriseDTO = wxEnterpriseService.selectById(wxEnterpriseId);
        if (wxEnterpriseDTO.getWxSecurityType() <= 0) {
            logger.info("WxSecurityType=0,wxEnterpriseId={}", wxEnterpriseId);
            return;
        }
        String corpid = wxEnterpriseDTO.getOpenCorpid();
        String corpName = wxEnterpriseDTO.getCorpName();
        String autoActiveStatus = qywxUserApiService.getAutoActiveStatus(corpid, serviceCorpid);
        if (!"1".equals(autoActiveStatus)) {
            logger.info("未开启自动激活：{},wxeid={}", corpid, wxEnterpriseId);
            this.wxEnterpriseService.updateAutoActiveFlagById(0, wxEnterpriseId);
            return;
        }
        Integer autoActiveFlag = wxEnterpriseDTO.getAutoActiveFlag();
        if (autoActiveFlag != null && autoActiveFlag != 1) {
            this.wxEnterpriseService.updateAutoActiveFlagById(1, wxEnterpriseId);
        }
        List<String> orderIdList = this.listOrderId(corpid);
        for (String orderId : orderIdList) {
            FeeOrderDeatilResponseDTO order = qywxUserApiService.getOrder(corpid, serviceCorpid, orderId);
            if (order.getErrcode() != 0) {
                logger.error("请求企微失败：{}", orderId);
                continue;
            }
            // 插入订单
            FeeOrderDeatilResponseDTO.OrderDTO orderDTO = order.getOrder();
            Integer orderStatus = orderDTO.getOrderStatus();
            if (orderStatus != 1) {
                logger.info("只处理已支付订单:{}", orderId);
                continue;
            }
            TabHaobanQywxFeeOrder tabHaobanQywxFeeOrder = new TabHaobanQywxFeeOrder();
            tabHaobanQywxFeeOrder.setFeeOrderId(UniqueIdUtils.uniqueLong());
            tabHaobanQywxFeeOrder.setOrderId(orderId);
            tabHaobanQywxFeeOrder.setCorpId(corpid);
            tabHaobanQywxFeeOrder.setWxEnterpriseId(wxEnterpriseId);
            tabHaobanQywxFeeOrder.setOrderType(orderDTO.getOrderType());
            tabHaobanQywxFeeOrder.setOrderStatus(orderStatus);
            tabHaobanQywxFeeOrder.setPrice(new BigDecimal(orderDTO.getPrice()));
            tabHaobanQywxFeeOrder.setBaseCount(orderDTO.getAccountCount().getBaseCount());
            tabHaobanQywxFeeOrder.setExternalContactCount(orderDTO.getAccountCount().getExternalContactCount());
            tabHaobanQywxFeeOrder.setMonths(orderDTO.getAccountDuration().getMonths());
            tabHaobanQywxFeeOrder.setCreateTime(DateUtil.date(orderDTO.getCreateTime() * 1000));
            tabHaobanQywxFeeOrder.setPayTime(DateUtil.date(orderDTO.getPayTime() * 1000));
            // 增加到订单表,如果存在不更新
            this.haobanQywxFeeOrderService.insert(tabHaobanQywxFeeOrder);
        }

        // 更新订单的激活码状态
        List<TabHaobanQywxFeeOrder> orderList = this.haobanQywxFeeOrderService.listOrder(wxEnterpriseId);
        if (CollectionUtils.isEmpty(orderList)) {
            logger.error("无企微订单：{}", wxEnterpriseId);
            return;
        }
        // 查询订单下的激活码code列表,记录到activeCodeList
        for (TabHaobanQywxFeeOrder order : orderList) {
            List<Map<String, String>> activeCodeList = new ArrayList<>();
            // 查询订单下的激活码code列表
            this.getOrderAccount(order.getOrderId(), corpid, null, activeCodeList);
            // 保存激活码列表
            this.addOrderAccount(wxEnterpriseId, serviceCorpid, corpid, activeCodeList);
        }

        // 成员的激活码信息
        this.staffService.activedAccountTimer(wxEnterpriseId);

        // 更新企业的激活数量统计
        WxEnterpriseQwDTO qwDTO =  this.wxEnterpriseService.getQwInfo(wxEnterpriseId) ;
        if(!qwDTO.isSelf()) {
            this.wxEnterpriseActiveDataService.saveOrUpdate(wxEnterpriseId);
        }

        // 统计 haobanQywxFeeDetailDTO 30天内最新过期的时间和人数
        HaobanQywxFeeDetailDTO haobanQywxFeeDetailDTO = haobanQywxFeeAccountStaffService.feeIntercept(wxEnterpriseId);
        // 剩余可用数量(状态1)
        int permissionUserNum = haobanQywxFeeOrderAccountService.countOrderAccountStatus(1, wxEnterpriseId);
        // 待转移数(状态4)
        int transferUserNum = haobanQywxFeeOrderAccountService.countOrderAccountStatus(4, wxEnterpriseId);
        int totalCount = this.haobanQywxFeeOrderService.countExternalContactCount(wxEnterpriseId);
        if (haobanQywxFeeDetailDTO != null) {
            TabHaobanQywxFee tabHaobanQywxFee = new TabHaobanQywxFee();
            tabHaobanQywxFee.setQwFeeId(UniqueIdUtils.uniqueLong());
            tabHaobanQywxFee.setCorpName(corpName);
            tabHaobanQywxFee.setCorpId(corpid);
            tabHaobanQywxFee.setWxEnterpriseId(wxEnterpriseId);
            tabHaobanQywxFee.setInterceptTime(haobanQywxFeeDetailDTO.getInterceptTime());
            tabHaobanQywxFee.setInterceptUserNum(haobanQywxFeeDetailDTO.getInterceptUserNum());
            tabHaobanQywxFee.setPermissionUserNum(permissionUserNum);
            tabHaobanQywxFee.setTransferUserNum(transferUserNum);
            tabHaobanQywxFee.setBuyPermissionUserNum(totalCount);
            tabHaobanQywxFee.setInterceptFlag(0);
            haobanQywxFeeService.insert(tabHaobanQywxFee);
            // 判断今天是否是本月最后一天
            if (DateUtil.isSameDay(DateUtil.endOfMonth(new Date()), new Date()) || "ca66a01b79474c40b3e7c7f93daf1a3b".equals(wxEnterpriseId)) {
                int monthWillInterceptNum = haobanQywxFeeDetailDTO.getInterceptUserNum() ;
                String content = "30天将有" + monthWillInterceptNum + "个接口许可证即将过期，您总共还剩余" + permissionUserNum
                        + "个可用的接口许可证，请保证数量充足，如需增加请及时联系相关人员续费，避免影响使用";
                messageAlert(wxEnterpriseId, corpName, corpid, AlertTypeEnum.FEE_ALARM.getName(), content);
            }
        }

        // 更加企微通知记录已拦截数
        List<TabHaobanQywxFeeAccountInterceptLog> interceptLogs = haobanQywxFeeAccountInterceptLogService
                .queryByWxEnterpriseId(wxEnterpriseId);
        if (CollectionUtils.isNotEmpty(interceptLogs)) {
            TabHaobanQywxFee tabHaobanQywxFee = new TabHaobanQywxFee();
            tabHaobanQywxFee.setQwFeeId(UniqueIdUtils.uniqueLong());
            tabHaobanQywxFee.setCorpName(corpName);
            tabHaobanQywxFee.setCorpId(corpid);
            tabHaobanQywxFee.setWxEnterpriseId(wxEnterpriseId);
            tabHaobanQywxFee.setInterceptTime(DateUtil.offsetDay(new Date(), -1));
            tabHaobanQywxFee.setInterceptUserNum(interceptLogs.size());
            tabHaobanQywxFee.setPermissionUserNum(permissionUserNum);
            tabHaobanQywxFee.setTransferUserNum(transferUserNum);
            tabHaobanQywxFee.setBuyPermissionUserNum(totalCount);
            tabHaobanQywxFee.setInterceptFlag(1);
            haobanQywxFeeService.insert(tabHaobanQywxFee);
        }
    }

    // 保存订单下的激活码信息-tab_haoban_qywx_fee_order_account
    private void addOrderAccount(String wxEnterpriseId, String serviceCorpid, String corpid,
            List<Map<String, String>> activeCodeList) {
        if (CollectionUtils.isEmpty(activeCodeList)) {
            logger.error("订单账号无激活码");
            return;
        }

        List<String> codeList = new ArrayList<>();
        Map<String, String> keyMap = new HashMap<>();
        for (Map<String, String> activeCodeMap : activeCodeList) {
            String activeCode = activeCodeMap.get("activeCode");
            String orderId = activeCodeMap.get("orderId");
            codeList.add(activeCode);
            keyMap.put(activeCode, orderId);
        }

        TabHaobanQywxFeeOrderAccount activeAccount = new TabHaobanQywxFeeOrderAccount();
        // 查询激活码的详情
        List<ActiveInfoCodeResponseDTO> respList = qywxUserApiService.getActiveInfoByCodeList(corpid, serviceCorpid,
                codeList);
        if (CollectionUtils.isNotEmpty(respList)) {
            List<List<ActiveInfoCodeResponseDTO>> list = Lists.partition(respList, 800);
            for (int i = 0; i < list.size(); i++) {
                List<ActiveInfoCodeResponseDTO> subList = list.get(i);
                for (ActiveInfoCodeResponseDTO activeDetail : subList) {
                    String userid = activeDetail.getUserid();
                    String activeCode = activeDetail.getActiveCode();
                    activeAccount.setWxUserId(userid);
                    activeAccount.setStatus(activeDetail.getStatus());
                    if (null != activeDetail.getExpireTime()) {
                        activeAccount.setExpireTime(DateUtil.date(activeDetail.getExpireTime() * 1000));
                        activeAccount.setActiveTime(DateUtil.date(activeDetail.getActiveTime() * 1000));
                    }
                    activeAccount.setAccountType(2);
                    activeAccount.setOrderId(keyMap.get(activeCode));
                    activeAccount.setActiveCode(activeCode);
                    activeAccount.setCorpId(corpid);
                    activeAccount.setWxEnterpriseId(wxEnterpriseId);
                    haobanQywxFeeOrderAccountService.save(activeAccount);
                }
            }
        }
    }

    @Override
    public Page<HaobanQywxFeeDTO> listPage(QywxFeeListQDTO qywxFeeListQDTO) {
        Page<HaobanQywxFeeBO> haobanQywxFeeBOS = haobanQywxFeeService.listPage(qywxFeeListQDTO);
        return PageUtil.changeToCurrentPage(haobanQywxFeeBOS, HaobanQywxFeeDTO.class);
    }

    @Override
    public List<HaobanQywxFeeDetailDTO> feeDetail(String wxEnterpriseId) {
        return haobanQywxFeeAccountStaffService.feeDetail(wxEnterpriseId);
    }

    @Override
    public void addInterceptLog(String param) {
        HaobanQywxFeeAccountInterceptLogDTO logDTO = JSON.toJavaObject(JSON.parseObject(param),
                HaobanQywxFeeAccountInterceptLogDTO.class);
        logDTO.setFeeAccountInterceptId(UniqueIdUtils.uniqueLong());
        TabHaobanWxEnterprise haobanWxEnterprise = wxEnterpriseService.getEnterpriseBycorpId(logDTO.getCorpId());
        if (null == haobanWxEnterprise) {
            return;
        }
        String wxEnterpriseId = haobanWxEnterprise.getWxEnterpriseId();
        logDTO.setWxEnterpriseId(wxEnterpriseId);
        TabHaobanStaff tabHaobanStaff = staffService.selectByUserIdAndEnterpriseId(logDTO.getWxUserId(),
                wxEnterpriseId);
        if (null == tabHaobanStaff) {
            return;
        }
        logDTO.setStaffId(tabHaobanStaff.getStaffId());
        haobanQywxFeeAccountInterceptLogService
                .insert(EntityUtil.changeEntityNew(TabHaobanQywxFeeAccountInterceptLog.class, logDTO));
    }

    @Override
    public HaobanQywxFeeDTO queryByWxEnterpriseId(String wxEnterpriseId) {
        return EntityUtil.changeEntityNew(HaobanQywxFeeDTO.class,
                haobanQywxFeeService.queryByWxEnterpriseId(wxEnterpriseId));
    }

    private void messageAlert(String wxEnterpriseId, String corpName, String corpid, String titleSub, String content) {
        ProviderLocalTag providerLocalTag = ProviderLocalTag.tag.get();
        String traceId = providerLocalTag.traceId;
        AlertMessageDTO messageDTO = new AlertMessageDTO();
        messageDTO.setAlertTitle(titleSub);
        messageDTO.setAlertType(AlertTypeEnum.FEE_ALARM.getType());
        messageDTO.setWxEnterpriseId(wxEnterpriseId);
        Map<String, Object> map = new HashMap<>();
        map.put("企业名称", corpName);
        map.put("企业id", corpid);
        map.put("内容", content);
        messageDTO.setContentMap(map);
        messageDTO.setTraceId(traceId);
        GicMQClient clientInstance = GICMQClientUtil.getClientInstance();
        try {
            clientInstance.sendMessage("haobanAlertMq", JSONObject.toJSONString(messageDTO), 6 * 3600);
        } catch (Exception e) {
            logger.info("异常：{}", e.getMessage(), e);
        }
    }
}
