package com.chinaweal.aiccs.schedule;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.chinaweal.aiccs.aiccs.abnormal.entity.EBaseinfo;
import com.chinaweal.aiccs.aiccs.abnormal.service.EBaseinfoService;
import com.chinaweal.aiccs.aiccs.market.ai.AreaSliceClaimAI;
import com.chinaweal.aiccs.aiccs.market.entity.AddressAssign;
import com.chinaweal.aiccs.aiccs.market.entity.AreaSlice;
import com.chinaweal.aiccs.aiccs.market.entity.EntAddressChangeLog;
import com.chinaweal.aiccs.aiccs.market.entity.dto.AssignEntity;
import com.chinaweal.aiccs.aiccs.market.service.AddressAssignService;
import com.chinaweal.aiccs.aiccs.market.service.AreaSliceService;
import com.chinaweal.aiccs.aiccs.market.service.IEntAddressChangeLogService;
import com.chinaweal.aiccs.aiccs.market.service.InitService;
import com.chinaweal.aiccs.common.util.StringUtils;
import com.chinaweal.youfool.framework.springboot.exception.custom.BusinessException;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.hadoop.classification.InterfaceAudience;
import org.mybatis.spring.MyBatisSystemException;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.Scheduled;

import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 自动认领定时任务
 *
 * @author <a href="https://blog.lroyia.top">lroyia</a>
 * @since 2021/5/25 10:08
 **/
@Configuration
@Slf4j(topic = "claim")
public class SliceAutoClaimScheduled {


    // 线程工厂，用于为线程池中的每条线程命名
    private static ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("assignAI-%d").build();

    // 创建线程池，使用有界阻塞队列防止内存溢出
    private static ExecutorService statsThreadPool = new ThreadPoolExecutor(3, 5,
            0L, TimeUnit.MILLISECONDS,
            new LinkedBlockingQueue<>(100), namedThreadFactory);

    @PreDestroy
    public void destroyed() {
        statsThreadPool.shutdown();
    }

    @Resource
    private AreaSliceClaimAI areaSliceClaimAI;
    @Resource
    private EBaseinfoService eBaseinfoService;
    @Resource
    private InitService initService;
    @Resource
    private AreaSliceService areaSliceService;
    @Resource
    private IEntAddressChangeLogService iEntAddressChangeLogService;
    @Resource
    private AddressAssignService addressAssignService;


    /**
     * 市场所主体补认领
     *
     * @author ymc
     * @since 2022年5月6日 17:19
     */
    @Scheduled(cron = "${scheduling.cron.repairAssignOwner}")
    public void repairAssignOwner() {
        log.info("==========市场所主体补认领开始==========");
        Set<String> notAreaSet = new HashSet<>();
        List<EBaseinfo> eBaseinfos = eBaseinfoService.lambdaQuery().isNull(EBaseinfo::getSareacodeTemp).eq(EBaseinfo::getRegstate, "1").orderByAsc(EBaseinfo::getPripid).last("limit 10000").list();
        while (CollectionUtils.isNotEmpty(eBaseinfos)) {
            String orgCode = null;
            String errPriPid = null;
            try {
                for (EBaseinfo each : eBaseinfos) {
                    // 2.根据监管、登记机关字段判断区域
                    orgCode = each.getSuporg();
                    errPriPid = each.getPripid();

                    // 过滤
                    if (StringUtils.isBlank(orgCode) || orgCode.length() == 6)
                        continue;

                    // 特殊处理
                    if ("44011006".equals(orgCode)) orgCode = "44011001";

                    // 区、所公共片区都只有一条数据，有多那就证明数据不正常，捕获一下顺便清晰一波数据
                    AreaSlice areaSlice = null;
                    areaSlice = areaSliceService.lambdaQuery().eq(AreaSlice::getOrgNumber, orgCode).eq(AreaSlice::getState, "1").in(AreaSlice::getSliceType, "0", "1").one();

                    if (areaSlice == null) {
                        notAreaSet.add(orgCode);
                        log.error("无法找到对应片区, pripid: {}, orgCode: {}。", each.getPripid(), orgCode);
                        continue;
                    }

                    initService.repairAssignOwner(areaSlice.getSliceId(), each.getPripid());

                }
                String pripid = eBaseinfos.get(eBaseinfos.size() - 1).getPripid();
                eBaseinfos = eBaseinfoService.lambdaQuery().isNull(EBaseinfo::getSareacodeTemp).eq(EBaseinfo::getRegstate, "1").gt(EBaseinfo::getPripid, pripid).orderByAsc(EBaseinfo::getPripid).last("limit 10000").list();
                log.info("遍历查询：pripid：{}, 数量：{} ", pripid, eBaseinfos.size());

            } catch (MyBatisSystemException e) {
                log.error("获取片区出错，orgCode: {}, 原因： {}", orgCode, e.getMessage());
            } catch (Exception e) {
                log.error("系统出错, pripid: {}, orgCode: {}。原因：", errPriPid, orgCode, e);
            }
        }
        log.info("没有片区数据集合：{}", String.join(",", notAreaSet));
        log.info("==========市场所主体补认领结束==========");
    }

    /**
     * 智能自动认领
     *
     * @author lroyia
     * @since 2021年11月28日 17:16:34
     */
    @Scheduled(cron = "${scheduling.cron.autoClaimAIByAddress}")
    public void autoClaimAIByAddress() {
        List<AddressAssign> domList = addressAssignService.list(new LambdaQueryWrapper<AddressAssign>()
                .eq(AddressAssign::getState, "0"));

        if(CollectionUtils.isNotEmpty(domList)){
            for(AddressAssign atom : domList){
                AreaSlice slice = areaSliceService.getOne(new LambdaQueryWrapper<AreaSlice>()
                        .eq(AreaSlice::getOrgNumber, atom.getOrgNumber())
                        .eq(AreaSlice::getSliceType, "1")
                        .eq(AreaSlice::getState, "1")
                        .eq(AreaSlice::getIsDeleted, "0"));

                if(slice != null){
                    String lastSql = "limit 10000";
                    List<EBaseinfo> records = eBaseinfoService.lambdaQuery()
                            .ne(EBaseinfo::getSuporg, atom.getOrgNumber())
                            .eq(EBaseinfo::getRegstate, "1")
                            .likeRight(EBaseinfo::getDom, atom.getAddress())
                            .orderByAsc(EBaseinfo::getPripid).last(lastSql).list();

                    while (CollectionUtils.isNotEmpty(records)) {
                        for (EBaseinfo each : records) {
                            if(!atom.getType().equals("0")){
                                String s = each.getDom().split(atom.getAddress())[1].split("号")[0];
                                String regex = "[0-9]+";
                                Pattern pattern = Pattern.compile(regex);
                                Matcher matcher = pattern.matcher(s);
                                if(!matcher.matches()){
                                    continue;
                                }
                                int number = Integer.parseInt(s) % 2;//判断单双
                                if(atom.getType().equals("1") && number == 0){
                                    continue;
                                }else if(atom.getType().equals("2") && number == 1){
                                    continue;
                                }
                            }
                            areaSliceClaimAI.claimByAddress(each, slice, atom.getOrgNumber(), atom.getOperator());
                        }
                        records = eBaseinfoService.lambdaQuery()
                                .ne(EBaseinfo::getSuporg, atom.getOrgNumber())
                                .eq(EBaseinfo::getRegstate, "1")
                                .likeRight(EBaseinfo::getDom, atom.getAddress())
                                .gt(EBaseinfo::getPripid, records.get(records.size() - 1).getPripid())
                                .orderByAsc(EBaseinfo::getPripid).last(lastSql).list();
                    }

                }
                addressAssignService.updateById(atom.setState("1"));
            }
        }
    }

    /**
     * 智能自动认领
     *
     * @author lroyia
     * @since 2021年11月28日 17:16:34
     */
    @Scheduled(cron = "${scheduling.cron.autoClaimAI}")
    public void autoClaimAI() {
        statsThreadPool.submit(() -> {
            log.info("==========市场所主体认领开始==========");

            String lastSql = "limit 10000";
            List<EBaseinfo> records = eBaseinfoService.lambdaQuery().isNull(EBaseinfo::getSareacodeTemp).eq(EBaseinfo::getRegstate, "1")
                    .orderByAsc(EBaseinfo::getPripid).last(lastSql).list();

            while (CollectionUtils.isNotEmpty(records)) {
                for (EBaseinfo each : records) {
                    ///有退还id的主体不做自动认领
                    if(StringUtils.isNotBlank(each.getAssignId())){
                        continue;
                    }

                    AssignEntity entity = new AssignEntity()
                            .setAddress(StringUtils.isNotBlank(each.getDom()) ? each.getDom() : each.getAddress())
                            .setPripid(each.getPripid())
                            .setEntName(each.getEntname())
                            .setEntType(each.getEnttype())
                            .setLerep(each.getLerep())
                            .setRegNo(each.getRegno())
                            .setRegOrg(each.getRegorg())
                            .setRegulatory(each.getSuporg())
                            .setUniscid(each.getUniscid());

//                    if (StringUtils.isBlank(entity.getAddress())) {
//                        log.error("缺失地址，pripid: {}", entity.getPripid());
//                        continue;
//                    }

                    try {
                        areaSliceClaimAI.claimInScope(entity, null);
                    } catch (Exception e) {
                        if ("配额不足".equals(e.getMessage())) {
                            log.error("高德地图配额不足,退出智能自动认领!", e);
                            break;
                        } else {
                            log.error("系统出错, pripid: {}。原因：", each.getPripid(), e);
                        }
                    }

                }
                records = eBaseinfoService.lambdaQuery().isNull(EBaseinfo::getSareacodeTemp).eq(EBaseinfo::getRegstate, "1")
                        .gt(EBaseinfo::getPripid, records.get(records.size() - 1).getPripid())
                        .orderByAsc(EBaseinfo::getPripid).last(lastSql).list();
            }

            log.info("==========市场所主体认领结束==========");

        });
    }

    /**
     * 智能自动认领（因住所变更）
     *
     * @author ymc
     * @since 2022年7月7日 19:10
     */
    @Scheduled(cron = "${scheduling.cron.autoClaimAIForAddressChange}")
    public void autoClaimAIForAddressChange() {
        statsThreadPool.submit(() -> {
            log.info("==========智能自动认领（因住所变更）开始==========");


            // 根据状态查出住所变更审计表需重新认领企业
            List<EntAddressChangeLog> records = iEntAddressChangeLogService.lambdaQuery().eq(EntAddressChangeLog::getStatus, "0").list();

            List<EntAddressChangeLog> oldList = new ArrayList<>();
            for (EntAddressChangeLog ebaseinfoUpdateAudit : records) {



                try {
                    // 用于判断泰富重复垃圾脏数据
                    oldList = iEntAddressChangeLogService.lambdaQuery()
                            .eq(EntAddressChangeLog::getPripid, ebaseinfoUpdateAudit.getPripid())
                            .eq(EntAddressChangeLog::getAfterAddress, ebaseinfoUpdateAudit.getAfterAddress())
                            .eq(EntAddressChangeLog::getBeforeAddress, ebaseinfoUpdateAudit.getBeforeAddress())
                            .eq(EntAddressChangeLog::getChangeDate, ebaseinfoUpdateAudit.getChangeDate())
                            .eq(EntAddressChangeLog::getStatus, "1").list();

                    if (oldList.size() == 0) {
                        EBaseinfo eBaseinfo = eBaseinfoService.getOneByPripid(ebaseinfoUpdateAudit.getPripid());
                        //避免主体表信息慢于变更更新造成的错误认领
                        if(eBaseinfo != null && eBaseinfo.getDom().trim().equals(ebaseinfoUpdateAudit.getAfterAddress().trim())){
                            iEntAddressChangeLogService.autoClaimAIForAddressChange(ebaseinfoUpdateAudit);
                            // 更新住所变更审计表状态
                            iEntAddressChangeLogService.updateById(ebaseinfoUpdateAudit.setStatus("1").setAssignTime(LocalDateTime.now()));
                        }
                    } else {
                        log.info("智能自动认领: 垃圾脏数据，id: {}, pripid: {}", ebaseinfoUpdateAudit.getId(), ebaseinfoUpdateAudit.getPripid());
                        // 更新住所变更审计表状态
                        iEntAddressChangeLogService.updateById(ebaseinfoUpdateAudit.setStatus("1").setAssignTime(LocalDateTime.now()));
                    }
                } catch (Exception e) {
                    log.error("智能自动认领（因住所变更）出错, pripid: {}。原因：", ebaseinfoUpdateAudit.getPripid(), e);
                }

            }

            log.info("==========智能自动认领（因住所变更）结束==========");

        });
    }
}
