package com.chinaweal.aiccs.aiccs.revoke.schedule;

import com.chinaweal.aiccs.aiccs.entbase.entity.TREntBase;
import com.chinaweal.aiccs.aiccs.entbase.service.TREntBaseService;
import com.chinaweal.aiccs.aiccs.revoke.entity.EGtRevoke;
import com.chinaweal.aiccs.aiccs.revoke.entity.ERevoke;
import com.chinaweal.aiccs.aiccs.revoke.entity.Revokelist;
import com.chinaweal.aiccs.aiccs.revoke.mapper.RevokelistMapper;
import com.chinaweal.aiccs.aiccs.revoke.service.IEGtRevokeService;
import com.chinaweal.aiccs.aiccs.revoke.service.IERevokeService;
import com.chinaweal.aiccs.redis.RedisService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;

/**
 * 吊销数据同步定时任务
 * <p>
 * 扫描REVOKELIST表，将未同步的数据根据市场主体类型分别写入E_REVOKE表或E_GT_REVOKE表
 * - 个体户（enttype为9500或9910）写入E_GT_REVOKE表
 * - 其他市场主体写入E_REVOKE表
 *
 * @author system
 * @since 2026-03-27
 */
@Slf4j
@Configuration
@EnableScheduling
public class RevokeSyncScheduled {

    /**
     * Redis锁key
     */
    private static final String REDIS_LOCK_KEY = "schedule:syncRevokeData:lock";

    /**
     * Redis锁超时时间（秒）
     */
    private static final int REDIS_LOCK_TIMEOUT = 30 * 60; // 30分钟

    /**
     * 个体户类型编码
     */
    private static final String ENTTYPE_INDIVIDUAL_9500 = "9500";
    private static final String ENTTYPE_INDIVIDUAL_9910 = "9910";

    @Autowired
    private RevokelistMapper revokelistMapper;

    @Autowired
    private IERevokeService eRevokeService;

    @Autowired
    private IEGtRevokeService eGtRevokeService;

    @Autowired
    private TREntBaseService trEntBaseService;

    @Autowired
    private RedisService redisService;

    /**
     * 定时同步吊销数据
     * 将REVOKELIST表中未同步的数据根据市场主体类型分别写入E_REVOKE或E_GT_REVOKE表
     */
    @Scheduled(cron = "${scheduling.cron.syncRevokeData:-}")
    @Transactional(rollbackFor = Exception.class)
    public void syncRevokeData() {
        // 检查Redis并发锁
        if (!acquireLock()) {
            log.warn("【吊销数据同步任务】上一次执行尚未完成或锁已存在，本次跳过");
            return;
        }

        try {
            doSync();
        } catch (Exception e) {
            log.error("【吊销数据同步任务】执行异常：{}", e.getMessage(), e);
            throw e;
        } finally {
            releaseLock();
        }
    }

    /**
     * 执行数据同步
     */
    private void doSync() {
        log.info("【吊销数据同步任务】开始执行");

        int pageSize = 100;
        int successCount = 0;
        int failCount = 0;
        int batchNum = 0;
        String lastRevlistId = null;

        while (true) {
            // 切片查询未同步的记录
            List<Revokelist> unsyncedList = getUnsynchronizedRevokelist(lastRevlistId, pageSize);
            if (unsyncedList.isEmpty()) {
                log.info("【吊销数据同步任务】没有更多需要同步的数据，任务结束");
                break;
            }

            batchNum++;
            log.info("【吊销数据同步任务】正在处理第{}批，记录数：{}", batchNum, unsyncedList.size());

            // 更新lastRevlistId为当前批次的最后一条记录主键
            lastRevlistId = unsyncedList.get(unsyncedList.size() - 1).getRevlistid();

            for (Revokelist revokelist : unsyncedList) {
                try {
                    // 根据PRIPID查询市场主体详细信息
                    TREntBase entBase = trEntBaseService.getById(revokelist.getPripid());
                    if (entBase == null) {
                        log.warn("【吊销数据同步任务】市场主体信息不存在，PRIPID：{}", revokelist.getPripid());
                        failCount++;
                        continue;
                    }

                    String enttype = entBase.getEnttype();
                    LocalDateTime now = LocalDateTime.now();

                    // 根据市场主体类型判断写入目标表
                    if (isIndividual(enttype)) {
                        // 个体户写入E_GT_REVOKE表
                        EGtRevoke eGtRevoke = buildEGtRevoke(revokelist, now);
                        eGtRevokeService.save(eGtRevoke);
                        log.debug("【吊销数据同步任务】个体户数据已写入，PRIPID：{}", revokelist.getPripid());
                    } else {
                        // 其他市场主体写入E_REVOKE表
                        ERevoke eRevoke = buildERevoke(revokelist, now);
                        eRevokeService.save(eRevoke);
                        log.debug("【吊销数据同步任务】企业数据已写入，PRIPID：{}", revokelist.getPripid());
                    }
                    successCount++;
                } catch (Exception e) {
                    log.error("【吊销数据同步任务】数据同步失败，PRIPID：{}，错误信息：{}", revokelist.getPripid(), e.getMessage(), e);
                    failCount++;
                }
            }
        }

        log.info("【吊销数据同步任务】执行完成，共处理{}批，成功：{}，失败：{}", batchNum, successCount, failCount);
    }

    /**
     * 获取分布式锁
     *
     * @return true-获取锁成功，false-锁已存在
     */
    private boolean acquireLock() {
        // 检查锁是否存在
        if (redisService.exists(REDIS_LOCK_KEY)) {
            return false;
        }
        // 设置锁，30分钟超时
        redisService.set(REDIS_LOCK_KEY, "1", REDIS_LOCK_TIMEOUT);
        return true;
    }

    /**
     * 释放分布式锁
     */
    private void releaseLock() {
        redisService.remove(REDIS_LOCK_KEY);
        log.debug("【吊销数据同步任务】Redis锁已释放");
    }

    /**
     * 切片查询未同步的REVOKELIST记录
     * 使用EXISTS语句判断E_REVOKE和E_GT_REVOKE表是否已存在该PRIPID
     *
     * @param lastRevlistId 上一次查询的最后一条主键ID，初始为null
     * @param pageSize      每页记录数
     * @return 未同步的REVOKELIST记录列表
     */
    private List<Revokelist> getUnsynchronizedRevokelist(String lastRevlistId, int pageSize) {
        return revokelistMapper.selectUnsyncedRevokelistBySlice(lastRevlistId, pageSize);
    }

    /**
     * 判断是否为个体户
     *
     * @param enttype 市场主体类型编码
     * @return true-是个体户，false-不是个体户
     */
    private boolean isIndividual(String enttype) {
        return ENTTYPE_INDIVIDUAL_9500.equals(enttype) || ENTTYPE_INDIVIDUAL_9910.equals(enttype);
    }

    /**
     * 构建E_REVOKE实体
     */
    private ERevoke buildERevoke(Revokelist revokelist, LocalDateTime now) {
        ERevoke eRevoke = new ERevoke();
        eRevoke.setPripid(revokelist.getPripid());
        // REVDATE字段映射：revokelist的REVOKEDATE转换为LocalDate
        if (revokelist.getRevokedate() != null) {
            eRevoke.setRevdate(revokelist.getRevokedate().toLocalDate());
        }
        // ILLEGACT字段映射：revokelist的REVOKEREA存储吊销原因
        eRevoke.setIllegact(revokelist.getRevokeRea());
        // REVAUTH字段映射：revokelist的PUNISHORGCN存储处罚机关
        eRevoke.setRevauth(revokelist.getPunishOrgCn());
        // REVBASIS字段：可以从CASENO或WRITSID获取，此处暂时留空
        eRevoke.setRevbasis(null);
        // S_EXT_FROMNODE字段：数据汇总单位，从LAUPTIME或其他字段获取
        eRevoke.setSExtFromnode("150000");
        eRevoke.setSExtDatatime(now);
        return eRevoke;
    }

    /**
     * 构建EGtRevoke实体
     */
    private EGtRevoke buildEGtRevoke(Revokelist revokelist, LocalDateTime now) {
        EGtRevoke eGtRevoke = new EGtRevoke();
        eGtRevoke.setPripid(revokelist.getPripid());
        // REVREA字段映射：revokelist的REVOKEREA存储吊销原因
        eGtRevoke.setRevrea(revokelist.getRevokeRea());
        // REVDATE字段映射：revokelist的REVOKEDATE转换为LocalDate
        if (revokelist.getRevokedate() != null) {
            eGtRevoke.setRevdate(revokelist.getRevokedate().toLocalDate());
        }
        // S_EXT_FROMNODE字段：数据汇总单位
        eGtRevoke.setSExtFromnode("150000");
        eGtRevoke.setSExtDatatime(now);
        return eGtRevoke;
    }
}
