package com.limap.quartz.task;

import com.alibaba.fastjson2.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.limap.core.basic.domain.*;
import com.limap.core.basic.service.IAquPayOrderService;
import com.limap.core.basic.service.IBasicProfitSharingRecordService;
import com.limap.core.basic.service.IBasicProfitSharingUserService;
import com.limap.core.basic.service.IBasicUserBindInfoService;
import com.limap.core.basic.vo.SharingUserTaskVo;
import lombok.extern.slf4j.Slf4j;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 分润计算定时任务
 * @author jjb
 */
@Component("profitTask")
@Slf4j
public class ProfitTask {

    @Resource
    private IBasicProfitSharingRecordService basicProfitSharingRecordService;
    @Resource
    private IBasicProfitSharingUserService sharingUserService;
    @Resource
    private IAquPayOrderService aquPayOrderService;
    @Autowired
    private IBasicUserBindInfoService basicUserBindInfoService;

    public void execute(Integer hour) {
        log.info("=== 分润计算定时任务开始, hour={} ===", hour);
        // 步骤1: 查询待处理订单
        List<AquPayDevice> list = aquPayOrderService.selectInfoByHour(hour);
        log.info("[步骤1] 查询到待处理订单数量: {}", list == null ? 0 : list.size());
        if (list != null && list.size() > 0) {
            // 打印前5条订单的设备序列号，方便核对
            list.stream().limit(5).forEach(o -> log.info("[步骤1-样本] 订单id={}, serialNum={}, payAmount={}, deviceType={}, profitStatus={}",
                    o.getId(), o.getSerialNum(), o.getPayAmount(), o.getDeviceType(), o.getProfitStatus()));

            // 步骤2: 查询分润用户
            List<SharingUserTaskVo> sharingUserTaskVos = sharingUserService.selectBasicInfoList();
            log.info("[步骤2] 查询到分润用户数量: {}", sharingUserTaskVos == null ? 0 : sharingUserTaskVos.size());
            if (sharingUserTaskVos != null && sharingUserTaskVos.size() > 0) {
                sharingUserTaskVos.stream().limit(5).forEach(u -> log.info("[步骤2-样本] userId={}, deviceName={}, omRatio={}, controlRatio={}, type={}",
                        u.getUserId(), u.getDeviceName(), u.getOmRatio(), u.getControlRatio(), u.getType()));
            }

            boolean b = list.stream().anyMatch(e -> e.getDeviceType() == 2);
            if (b) {
                BasicProfitSharingUser byId = sharingUserService.getById(101);
                log.info("[步骤2-控制柜] 存在deviceType=2的订单, id=101的分润用户: {}", byId != null ? "存在" : "不存在");
                if (byId != null) {
                    list.stream().filter(e -> e.getDeviceType() == 2).forEach(e -> {
                        SharingUserTaskVo sharingUserTaskVo = new SharingUserTaskVo();
                        sharingUserTaskVo.setDeviceName(e.getSerialNum());
                        sharingUserTaskVo.setUserId(byId.getUserId());
                        sharingUserTaskVo.setControlRatio(byId.getControlRatio());
                        sharingUserTaskVo.setOmRatio(byId.getOmRatio());
                        sharingUserTaskVo.setType("2");
                        sharingUserTaskVos.add(sharingUserTaskVo);
                    });
                }
            }
            if (sharingUserTaskVos == null || sharingUserTaskVos.size() == 0) {
                log.info("[步骤2] 没有需要计算的用户，退出");
                return;
            }

            // 步骤3: 按设备名分组
            Map<String,List<SharingUserTaskVo>> collect = dealProfitUser(sharingUserTaskVos);
            log.info("[步骤3] dealProfitUser后设备分组数量: {}, 设备名keys(前10): {}",
                    collect.size(), collect.keySet().stream().limit(10).collect(Collectors.joining(", ")));

            // 步骤4: 匹配订单与分润用户
            List<BasicProfitSharingRecord> basicProfitSharingRecords = new ArrayList<>();
            List<AquPayDevice> aquPayOrders = new ArrayList<>();
            int matchCount = 0;
            int noMatchCount = 0;
            List<String> noMatchDevices = new ArrayList<>();
            for (AquPayDevice aquPayOrder : list) {
                try {
                    String deviceName = aquPayOrder.getSerialNum();
                    if (collect.containsKey(deviceName)) {
                        matchCount++;
                        List<SharingUserTaskVo> sharingUserTaskVos1 = collect.get(deviceName);
                        for (SharingUserTaskVo sharingUserTaskVo : sharingUserTaskVos1) {
                            try {
                                BasicProfitSharingRecord basicProfitSharingRecord = basicProfitSharingRecordService.calculateProfit(aquPayOrder, sharingUserTaskVo);
                                basicProfitSharingRecords.add(basicProfitSharingRecord);
                                aquPayOrder.setProfitStatus(1);
                                aquPayOrders.add(aquPayOrder);
                            } catch (Exception e) {
                                log.error("[步骤4] 订单id={}，serialNum={}，分润计算异常: {}", aquPayOrder.getId(), aquPayOrder.getSerialNum(), e.getMessage(), e);
                            }
                        }
                    } else {
                        noMatchCount++;
                        if (noMatchDevices.size() < 10) {
                            noMatchDevices.add(deviceName);
                        }
                    }
                } catch (Exception e) {
                    log.error("[步骤4] 订单id={}，处理异常: {}", aquPayOrder.getId(), e.getMessage(), e);
                }
            }
            log.info("[步骤4] 匹配成功: {}条, 未匹配: {}条, 生成分润记录: {}条", matchCount, noMatchCount, basicProfitSharingRecords.size());
            if (noMatchDevices.size() > 0) {
                log.info("[步骤4] 未匹配的设备名(前10): {}", String.join(", ", noMatchDevices));
            }

            // 步骤5: 批量保存
            if (basicProfitSharingRecords.size() > 0) {
                log.info("[步骤5] 准备批量保存分润记录: {}条, 更新订单状态: {}条", basicProfitSharingRecords.size(), aquPayOrders.size());
                try {
                    // 保存前查询记录数
                    long beforeCount = basicProfitSharingRecordService.count();
                    log.info("[步骤5] 保存前表中记录数: {}", beforeCount);

                    basicProfitSharingRecordService.saveBatch(basicProfitSharingRecords);

                    // 保存后立即查询验证
                    long afterCount = basicProfitSharingRecordService.count();
                    log.info("[步骤5] 保存后表中记录数: {}, 新增: {}", afterCount, afterCount - beforeCount);

                    if (afterCount > beforeCount) {
                        aquPayOrderService.updatePayDeviceStatus(aquPayOrders);
                        log.info("[步骤5] 批量保存成功, 实际新增{}条", afterCount - beforeCount);
                    } else {
                        log.error("[步骤5] 严重问题: saveBatch执行完毕但表中无新增数据! 可能是数据源路由问题");
                    }
                } catch (Exception e) {
                    log.error("[步骤5] 批量保存异常: {}", e.getMessage(), e);
                }
            } else {
                log.info("[步骤5] 没有生成任何分润记录，跳过保存");
            }
        } else {
            log.info("[步骤1] 没有需要计算的订单(hour={})", hour);
        }
        log.info("=== 分润计算定时任务结束 ===");
    }

    /**
     * 补录历史分润数据
     * 从4月8日至今约1300小时，调用方式: profitTask.backfill()
     * 或指定小时数: profitTask.backfillByHours(1300)
     * 注意: 此方法会忽略profit_status，查询所有订单，并通过order_no去重避免重复写入
     */
    public void backfill() {
        backfillByHours(1500);
    }

    public void backfillByHours(Integer hours) {
        log.info("===== 开始补录历史分润数据, 回溯{}小时 =====", hours);
        // 使用backfill专用查询，忽略profit_status
        List<AquPayDevice> list = aquPayOrderService.selectInfoForBackfill(hours);
        log.info("[补录] 查询到订单数量: {}", list == null ? 0 : list.size());
        if (list == null || list.isEmpty()) {
            log.info("[补录] 没有需要补录的订单");
            return;
        }

        // 查询已存在的分润记录order_no，用于去重
        List<BasicProfitSharingRecord> existingRecords = basicProfitSharingRecordService.list();
        Set<String> existingOrderNos = existingRecords.stream()
                .map(BasicProfitSharingRecord::getOrderNo)
                .filter(Objects::nonNull)
                .collect(Collectors.toSet());
        log.info("[补录] 已存在分润记录数: {}", existingOrderNos.size());

        // 过滤掉已有记录的订单
        List<AquPayDevice> needProcessList = list.stream()
                .filter(o -> !existingOrderNos.contains(String.valueOf(o.getOrderId())))
                .collect(Collectors.toList());
        log.info("[补录] 去重后需要处理的订单数: {}", needProcessList.size());

        if (needProcessList.isEmpty()) {
            log.info("[补录] 所有订单均已有分润记录，无需补录");
            return;
        }

        // 查询分润用户
        List<SharingUserTaskVo> sharingUserTaskVos = sharingUserService.selectBasicInfoList();
        log.info("[补录] 分润用户数量: {}", sharingUserTaskVos == null ? 0 : sharingUserTaskVos.size());

        // 处理deviceType=2的控制柜订单
        boolean hasControlDevice = needProcessList.stream().anyMatch(e -> e.getDeviceType() == 2);
        if (hasControlDevice) {
            BasicProfitSharingUser byId = sharingUserService.getById(101);
            if (byId != null) {
                needProcessList.stream().filter(e -> e.getDeviceType() == 2).forEach(e -> {
                    SharingUserTaskVo vo = new SharingUserTaskVo();
                    vo.setDeviceName(e.getSerialNum());
                    vo.setUserId(byId.getUserId());
                    vo.setControlRatio(byId.getControlRatio());
                    vo.setOmRatio(byId.getOmRatio());
                    vo.setType("2");
                    sharingUserTaskVos.add(vo);
                });
            }
        }

        if (sharingUserTaskVos == null || sharingUserTaskVos.isEmpty()) {
            log.info("[补录] 没有分润用户，退出");
            return;
        }

        Map<String, List<SharingUserTaskVo>> collect = dealProfitUser(sharingUserTaskVos);
        List<BasicProfitSharingRecord> records = new ArrayList<>();

        for (AquPayDevice order : needProcessList) {
            try {
                String deviceName = order.getSerialNum();
                if (collect.containsKey(deviceName)) {
                    for (SharingUserTaskVo vo : collect.get(deviceName)) {
                        try {
                            BasicProfitSharingRecord record = basicProfitSharingRecordService.calculateProfit(order, vo);
                            records.add(record);
                        } catch (Exception e) {
                            log.error("[补录] 订单id={}, 计算异常: {}", order.getId(), e.getMessage());
                        }
                    }
                }
            } catch (Exception e) {
                log.error("[补录] 订单id={}, 处理异常: {}", order.getId(), e.getMessage());
            }
        }

        log.info("[补录] 生成分润记录: {}条", records.size());
        if (!records.isEmpty()) {
            try {
                basicProfitSharingRecordService.saveBatch(records);
                log.info("[补录] 保存成功, 共{}条记录", records.size());
            } catch (Exception e) {
                log.error("[补录] 保存异常: {}", e.getMessage(), e);
            }
        }
        log.info("===== 补录历史分润数据完成 =====");
    }

    public void executeEquipmentBind() {
        // 查询需要补全的记录：device_id为空 或 app_user为空（小程序用户后绑定的情况）
        List<BasicUserBindInfo> needUpdateList = basicUserBindInfoService.list(
            new LambdaQueryWrapper<BasicUserBindInfo>()
                .and(w -> w.isNull(BasicUserBindInfo::getDeviceId)
                    .or().isNull(BasicUserBindInfo::getAppUser))
        );
        if (CollectionUtils.isEmpty(needUpdateList)) {
            log.info("没有需要补全的设备绑定记录");
            return;
        }
        log.info("[设备绑定补全] 待处理记录数: {}", needUpdateList.size());

        // 从aqu_device + aqu_user获取最新设备和用户信息
        List<BasicUserBindInfo> appUserInfo = basicUserBindInfoService.selectAppUserInfo();
        if (CollectionUtils.isEmpty(appUserInfo)) {
            log.info("[设备绑定补全] aqu_device中无设备数据");
            return;
        }

        Map<String, List<BasicUserBindInfo>> collect = appUserInfo.stream()
            .filter(e -> e != null && e.getDeviceName() != null)
            .collect(Collectors.groupingBy(BasicUserBindInfo::getDeviceName));

        List<BasicUserBindInfo> updateList = new ArrayList<>();
        for (BasicUserBindInfo record : needUpdateList) {
            if (collect.containsKey(record.getDeviceName())) {
                BasicUserBindInfo source = collect.get(record.getDeviceName()).get(0);
                // 创建新对象避免对象引用问题
                BasicUserBindInfo updateItem = new BasicUserBindInfo();
                updateItem.setId(record.getId());
                updateItem.setDeviceId(source.getDeviceId());
                updateItem.setIotId(source.getIotId());
                updateItem.setType(source.getType());
                updateItem.setBindTime(source.getBindTime());
                updateItem.setAppUser(source.getAppUser());
                updateItem.setAppUserName(source.getAppUserName());
                updateItem.setAppUserTel(source.getAppUserTel());
                updateList.add(updateItem);
            }
        }

        if (updateList.size() > 0) {
            basicUserBindInfoService.updateBatchById(updateList);
            log.info("[设备绑定补全] 成功更新{}条记录", updateList.size());
        } else {
            log.info("[设备绑定补全] 没有匹配到aqu_device中的设备");
        }
    }

    private Map<String,List<SharingUserTaskVo>> dealProfitUser(List<SharingUserTaskVo> sharingUserTaskVos){
        Map<String, List<SharingUserTaskVo>> collect = sharingUserTaskVos.stream()
                .filter(e -> e != null && e.getDeviceName() != null)
                .collect(Collectors.groupingBy(SharingUserTaskVo::getDeviceName));

        Map<String, List<SharingUserTaskVo>> result = new HashMap<>();
        collect.forEach((k, v) -> {
            List<SharingUserTaskVo> distinctList = distinctByUserId(v);
            List<SharingUserTaskVo> newList = new ArrayList<>();
            for (SharingUserTaskVo e : distinctList) {
                if (e != null && e.getParentId() != null) {
                    newList = dealParent(e,sharingUserTaskVos,newList);
                }else{
                    newList.add(e);
                }
            }
            result.put(k, distinctByUserId(newList));
        });

        return result;
    }

    public List<SharingUserTaskVo> dealParent(SharingUserTaskVo sharingUserTaskVo,List<SharingUserTaskVo> sharingUserTaskVos,List<SharingUserTaskVo> newList){
        List<SharingUserTaskVo> resultList = new ArrayList<>(newList); // 避免副作用
        SharingUserTaskVo current = sharingUserTaskVo;

        // 预处理数据，提高查找效率
        Map<Long, SharingUserTaskVo> userTaskMap = sharingUserTaskVos.stream()
                .filter(f -> f != null && f.getUserId() != null)
                .collect(Collectors.toMap(SharingUserTaskVo::getUserId, f -> f, (existing, replacement) -> existing));

        Set<Long> visited = new HashSet<>(); // 防止循环引用导致的无限循环

        while (current != null && current.getParentId() != null) {
            // 检查是否已经访问过该节点，防止循环引用
            if (visited.contains(current.getParentId())) {
                break;
            }
            visited.add(current.getParentId());

            SharingUserTaskVo parent = userTaskMap.get(current.getParentId());

            if (parent == null) {
                resultList.add(sharingUserTaskVo);
                break;
            }

            // 修正逻辑：只添加当前节点和父节点，而不是每次都添加原始节点
            if (current == sharingUserTaskVo) {
                resultList.add(sharingUserTaskVo);
            }
            resultList.add(parent);
            current = parent;
        }

        return resultList;
    }

    private List<SharingUserTaskVo> distinctByUserId(List<SharingUserTaskVo> list) {
        Map<Long, SharingUserTaskVo> map = new LinkedHashMap<>();
        for (SharingUserTaskVo item : list) {
            if (item == null) {
                continue;
            }
            Long userId = item.getUserId();
            if (userId == null) {
                continue;
            }
            map.putIfAbsent(userId, item);
        }
        return new ArrayList<>(map.values());
    }
}
