package org.dromara.zhishu.service.strategy;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.redis.utils.RedisUtils;
import org.dromara.common.sse.dto.SseMessageDto;
import org.dromara.common.sse.utils.SseMessageUtils;
import org.dromara.zhishu.domain.Shop;
import org.dromara.zhishu.domain.ZhishuShopGoods;
import org.dromara.zhishu.domain.bo.TaskBo;
import org.dromara.zhishu.domain.dto.request.ErpGoodsQueryOlnGoodsRequest;
import org.dromara.zhishu.domain.dto.request.GoodsComparisonRequest;
import org.dromara.zhishu.domain.dto.request.UpdateShopGoodsPriceRequest;
import org.dromara.zhishu.domain.dto.request.ZhishuShopGoodsRequest;
import org.dromara.zhishu.domain.dto.response.ErpGoodsQueryOlnGoodsResponse;
import org.dromara.zhishu.domain.dto.response.WlnBaseResponse;
import org.dromara.zhishu.domain.vo.ShopVo;
import org.dromara.zhishu.enums.TaskTypeEnum;
import org.dromara.zhishu.mapper.ShopMapper;
import org.dromara.zhishu.mapper.ZhishuShopGoodsMapper;
import org.dromara.zhishu.service.client.WlnClient;
import org.dromara.zhishu.service.impl.TaskServiceImpl;
import org.dromara.zhishu.util.CnumberUtils;
import org.dromara.zhishu.util.ExcelFileHandlerUtil;
import org.dromara.zhishu.util.ThreadPoolUtils;
import org.dromara.zhishu.util.UrlUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

import static cn.dev33.satoken.SaManager.log;

@Service
public class ShopGoodsWlnStrategy implements ShopGoodsStrategy {

    // 每隔多少秒续期一次 Redis 锁（比如 30 秒）
    private static final int INITIAL_DELAY_AND_PERIOD = 30;

    @Autowired
    private WlnClient wlnClient;

    @Autowired
    private ShopMapper shopMapper;

    @Autowired
    private ZhishuShopGoodsMapper zhishuShopGoodsMapper;

    @Autowired
    private ScheduledExecutorService scheduledExecutorService;

    @Autowired
    private TaskServiceImpl taskServiceImpl;

    @Async
    @Override
    public void synchronizationGoods(Long shopId) {
        // 根据店铺Id查询店铺信息
        Shop shopInfo = new LambdaQueryChainWrapper<>(shopMapper)
                .eq(Shop::getId, shopId)
                .oneOpt().orElseThrow(() -> new ServiceException("查询不到店铺信息：" + shopId));
        // 获取当前时间
        LocalDateTime now = LocalDateTime.now();
        // 定义格式：YYYY-MM-DD HH:mm:ss
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        // 格式化当前时间
        String currentDateTime = now.format(formatter);
        // 从Redis中获取上次同步时间
        String lastGoodsSynTime = (String) RedisUtils.getCacheObject("lastGoodsSynTime_" + shopInfo.getId());
        ThreadPoolUtils.execute(() -> {
            List<ErpGoodsQueryOlnGoodsResponse.Element> shopGoodsList = queryShopGoods(shopInfo.getAccount(), shopInfo.getPassword(), shopInfo.getShopNike(), lastGoodsSynTime);
            List<ZhishuShopGoodsRequest> zhishuShopGoodsRequestList = new ArrayList<>();
            for (ErpGoodsQueryOlnGoodsResponse.Element spu : shopGoodsList) {
                ZhishuShopGoodsRequest zhishuShopGoodsRequest = new ZhishuShopGoodsRequest();
                zhishuShopGoodsRequest.setUserId(shopInfo.getCreateBy().toString());
                zhishuShopGoodsRequest.setProductId(spu.getItemId());
                zhishuShopGoodsRequest.setStock(0L);
                zhishuShopGoodsRequest.setCreateBy(shopInfo.getCreateBy());
                zhishuShopGoodsRequest.setInventory(0);
                zhishuShopGoodsRequest.setGoodsName(spu.getTitle());
                zhishuShopGoodsRequest.setBookPic(spu.getPic());
                if (ObjectUtil.isNotEmpty(spu.getSkus())) {
                    for (ErpGoodsQueryOlnGoodsResponse.Element.Sku sku : spu.getSkus()) {
                        zhishuShopGoodsRequest.setGoodsName(sku.getName());
                        zhishuShopGoodsRequest.setItemNumber(sku.getSkuId());
                        if (ObjectUtil.isNotEmpty(sku.getPic())) zhishuShopGoodsRequest.setBookPic(sku.getPic());
                        zhishuShopGoodsRequestList.add(zhishuShopGoodsRequest);
                    }
                } else {
                    zhishuShopGoodsRequestList.add(zhishuShopGoodsRequest);
                }
            }
            GoodsComparisonRequest request = new GoodsComparisonRequest();
            request.setShopId(shopId);
            request.setUserId(shopInfo.getCreateBy());
            request.setZhishuShopGoodsRequestList(zhishuShopGoodsRequestList);
            request.setCurrentDateTime(currentDateTime);
            goodsComparison(request);
        });
    }

    // 获取万里牛商品列表
    public List<ErpGoodsQueryOlnGoodsResponse.Element> queryShopGoods(String appKey, String appSecret, String shopNick, String lastGoodsSynTime) {
        Boolean pageQueryFlag = true;
        List<ErpGoodsQueryOlnGoodsResponse.Element> shopGoodsList = new ArrayList<>();
        ErpGoodsQueryOlnGoodsRequest request = new ErpGoodsQueryOlnGoodsRequest();
        request.setShopNick(shopNick);
        while (pageQueryFlag) {
            WlnBaseResponse<ErpGoodsQueryOlnGoodsResponse> response = wlnClient.erpGoodsQueryOlnGoods(UrlUtil.getWlnServiceUrl(), appKey, appSecret, request);
            if (response.getCode() != 0) throw new ServiceException("获取万里牛商品列表失败：" + response.getMessage());
            if (ObjectUtil.isNotEmpty(response.getData())) {
                shopGoodsList.addAll(response.getData().getElements());
            }
            request.setPage(request.getPage() + 1);
            pageQueryFlag = response.getData().getNext();
        }
        return shopGoodsList;
    }


    // 比对店铺商品信息并生成Excel文件
    public void goodsComparison(GoodsComparisonRequest request) {
        Long shopId = request.getShopId();
        Long userId = request.getUserId();
        List<ZhishuShopGoodsRequest> zhishuShopGoodsRequestList = request.getZhishuShopGoodsRequestList();
        // 尝试获取锁
        String lockKey = "WriteExcelKey_" + shopId;
        String lockValue = "WriteExcelLock";
        Duration lockExpireDuration = Duration.ofMinutes(2); // 设置锁的过期时间为2分钟
        String writeExcelLock = RedisUtils.getCacheObject(lockKey);
        // 若获取存在说明存在读取该文件的线程，则直接返回，不进行后续操作
        if (ObjectUtil.isNotEmpty(writeExcelLock)) throw new ServiceException("已在处理该文件，请勿重复操作");
        System.out.println("获取到redis锁，执行读取文件操作");
        // 若不存在，则设置锁，并执行后续操作
        RedisUtils.setCacheObject(lockKey, lockValue, lockExpireDuration);
        ScheduledExecutorService scheduler = null;
        ScheduledFuture<?> future = null;
        try {
            scheduler = Executors.newScheduledThreadPool(1);
            // 设置一个定时任务来不断延长锁的过期时间
            Runnable renewLockTask = () -> {
                RedisUtils.setCacheObject(lockKey, lockValue, lockExpireDuration);
                System.out.println("Redis锁过期时间已更新");
            };
            // 启动定时任务
            future = scheduler.scheduleAtFixedRate(renewLockTask, 0, INITIAL_DELAY_AND_PERIOD, TimeUnit.SECONDS);

            // 使用并发流处理
            List<ZhishuShopGoodsRequest> changedData = Collections.synchronizedList(new ArrayList<>());
            List<ZhishuShopGoodsRequest> newData = Collections.synchronizedList(new ArrayList<>());

            for (ZhishuShopGoodsRequest zhishuShopGoodsRequest : zhishuShopGoodsRequestList) {
                if (!ObjectUtil.isEmpty(zhishuShopGoodsRequest.getItemNumber())) {
                    // 查出数据库是否存在数据
                    List<ZhishuShopGoods> list = new LambdaQueryChainWrapper<>(zhishuShopGoodsMapper)
                            .eq(ZhishuShopGoods::getItemNumber, zhishuShopGoodsRequest.getItemNumber())
                            .list();
                    if (!ObjectUtil.isNotEmpty(list)) {
                        newData.add(zhishuShopGoodsRequest);
                    }
                } else {
                    // 查出数据库是否存在数据
                    List<ZhishuShopGoods> list = new LambdaQueryChainWrapper<>(zhishuShopGoodsMapper)
                            .eq(ZhishuShopGoods::getProductId, zhishuShopGoodsRequest.getProductId())
                            .list();
                    if (!ObjectUtil.isNotEmpty(list)) {
                        newData.add(zhishuShopGoodsRequest);
                    }
                }
            }

            List<String> fileNameList = new ArrayList<>();
            // 分别指定新增和修改的数据生成的Excel文件存储路径，文件名称前缀，并写到该路径下
            if (!changedData.isEmpty()) {
                fileNameList.add("Changed_" + shopId + "_0.xlsx");
                ExcelFileHandlerUtil.handleExport(changedData, UrlUtil.getUrl(), "Changed", shopId.toString(), ZhishuShopGoodsRequest.class);
            }
            if (!newData.isEmpty()) {
                fileNameList.add("New_" + shopId + "_0.xlsx");
                ExcelFileHandlerUtil.handleExport(newData, UrlUtil.getUrl(), "New", shopId.toString(), ZhishuShopGoodsRequest.class);
            }


            RedisUtils.setCacheObject("lastGoodsSynTime_" + shopId, request.getCurrentDateTime());

            if (!newData.isEmpty() || !changedData.isEmpty()) {
                // 根据店铺Id查询店铺信息
                Shop shopInfo = new LambdaQueryChainWrapper<>(shopMapper)
                        .eq(Shop::getId, shopId)
                        .oneOpt().orElseThrow(() -> new ServiceException("查询不到店铺信息：" + shopId));
                // 将任务信息插入到数据库中，创建一条任务
                TaskBo taskBo = new TaskBo();
                taskBo.setTaskType(TaskTypeEnum.SYNC_GOODS_WLN.getCode());
                taskBo.setShopIds(shopId.toString());
                taskBo.setShopNames(shopInfo.getShopName());
                taskBo.setFileName(String.join("/", fileNameList));
                taskBo.setDataNum((long) zhishuShopGoodsRequestList.size());
                taskBo.setTaskStatus("0");
                taskBo.setStatus("0");
                taskBo.setCreateBy(userId);
                taskServiceImpl.insertByBo(taskBo);
            }

            // 发送消息给前端告知拉取下来的数据已比对完毕
            scheduledExecutorService.schedule(() ->

            {
                SseMessageDto dto = new SseMessageDto();
                dto.setMessage("已拉取到商品数据总计：" + zhishuShopGoodsRequestList.size() + "条，新增：" + newData.size() + "条新数据，更新：" + changedData.size() + "条数据");
                dto.setUserIds(List.of(userId));
                SseMessageUtils.publishMessage(dto);
            }, 5, TimeUnit.SECONDS);
        } catch (Exception e) {
            // 捕获其他未知异常
            log.error("商品导入写入Excel过程中发生异常: {}", e.getMessage(), e);
            throw new ServiceException(e.getMessage());
        } finally {
            // 取消定时任务
            if (future != null) {
                future.cancel(false);
            }
            // 关闭线程池
            if (scheduler != null) {
                scheduler.shutdownNow();
            }
            // 确保释放锁
            RedisUtils.deleteObject(lockKey);
            System.out.println("已释放redis锁");
        }

    }

    @Override
    public Boolean setShopGoodsOnSaleStatus(Long mallId, String token, Integer isOnSale, List<UpdateShopGoodsPriceRequest.Item> ItemList) {
        return false;
    }

    @Override
    public Boolean updateShopGoodsPrice(Long mallId, String token, List<UpdateShopGoodsPriceRequest.Item> ItemList) {
        return false;
    }


}
