package com.starry.admin.modules.withdraw.service.impl;

import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.starry.admin.common.exception.CustomException;
import com.starry.admin.modules.order.module.entity.PlayOrderInfoEntity;
import com.starry.admin.modules.order.service.IPlayOrderInfoService;
import com.starry.admin.modules.withdraw.entity.EarningsBackfillLogEntity;
import com.starry.admin.modules.withdraw.entity.EarningsLineEntity;
import com.starry.admin.modules.withdraw.service.IEarningsBackfillLogService;
import com.starry.admin.modules.withdraw.service.IEarningsBackfillService;
import com.starry.admin.modules.withdraw.service.IEarningsService;
import com.starry.admin.modules.withdraw.vo.BackfillOrderPreview;
import com.starry.admin.modules.withdraw.vo.EarningsBackfillRequest;
import com.starry.admin.modules.withdraw.vo.EarningsBackfillResponse;
import com.starry.admin.utils.SecurityUtils;
import com.starry.common.utils.IdUtils;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

@Service
public class EarningsBackfillServiceImpl implements IEarningsBackfillService {

    private static final DateTimeFormatter ISO_DATE_TIME = DateTimeFormatter.ISO_DATE_TIME;
    private static final DateTimeFormatter SIMPLE_DATE_TIME = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    @Resource
    private IPlayOrderInfoService orderInfoService;
    @Resource
    private IEarningsService earningsService;
    @Resource
    private IEarningsBackfillLogService backfillLogService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public EarningsBackfillResponse backfill(EarningsBackfillRequest request) {
        if (request == null) {
            throw new CustomException("参数不能为空");
        }
        String tenantId = SecurityUtils.getTenantId();
        if (tenantId == null) {
            throw new CustomException("租户上下文为空");
        }
        LocalDateTime begin = parseDate(request.getBeginTime());
        LocalDateTime end = parseDate(request.getEndTime());
        if (begin != null && end != null && begin.isAfter(end)) {
            throw new CustomException("起始时间不能晚于结束时间");
        }
        boolean dryRun = Boolean.TRUE.equals(request.getDryRun());

        LambdaQueryWrapper<PlayOrderInfoEntity> query = new LambdaQueryWrapper<>();
        query.eq(PlayOrderInfoEntity::getTenantId, tenantId)
                .eq(PlayOrderInfoEntity::getOrderStatus, "3");
        if (begin != null) {
            query.ge(PlayOrderInfoEntity::getOrderEndTime, begin);
        }
        if (end != null) {
            query.le(PlayOrderInfoEntity::getOrderEndTime, end);
        }
        if (!CollectionUtils.isEmpty(request.getClerkIds())) {
            query.in(PlayOrderInfoEntity::getAcceptBy, request.getClerkIds());
        }
        List<PlayOrderInfoEntity> orders = orderInfoService.list(query);
        if (orders.size() > 2000) {
            throw new CustomException("符合条件的订单过多，请缩小时间范围或筛选店员后再试");
        }

        int ordersChecked = 0;
        int createdCount = 0;
        int skippedExisting = 0;
        List<String> warnings = new ArrayList<>();
        List<BackfillOrderPreview> previews = new ArrayList<>();
        final int previewLimit = 50;

        for (PlayOrderInfoEntity order : orders) {
            ordersChecked++;
            BigDecimal amount = resolveAmount(order, warnings);
            if (amount == null) {
                continue;
            }
            if (hasExistingEarnings(tenantId, order.getId())) {
                skippedExisting++;
                continue;
            }
            if (previews.size() < previewLimit) {
                BackfillOrderPreview preview = new BackfillOrderPreview();
                preview.setOrderId(order.getId());
                preview.setClerkId(order.getAcceptBy());
                preview.setAmount(amount);
                preview.setOrderEndTime(order.getOrderEndTime());
                previews.add(preview);
            }
            if (dryRun) {
                createdCount++;
                continue;
            }
            earningsService.createFromOrder(order);
            if (hasExistingEarnings(tenantId, order.getId())) {
                createdCount++;
            } else {
                addWarning(warnings, "订单 " + order.getId() + " 创建收益失败");
            }
        }

        EarningsBackfillResponse response = new EarningsBackfillResponse();
        response.setDryRun(dryRun);
        response.setOrdersChecked(ordersChecked);
        response.setCreatedCount(createdCount);
        response.setSkippedExisting(skippedExisting);
        response.setWarnings(warnings);
        response.setOrders(previews);

        // persist log
        EarningsBackfillLogEntity log = new EarningsBackfillLogEntity();
        log.setId(IdUtils.getUuid());
        log.setTenantId(tenantId);
        log.setOperatorId(safe(SecurityUtils::getUserId));
        log.setOperatorName(safe(SecurityUtils::getUsername));
        log.setBackfillBeginTime(begin);
        log.setBackfillEndTime(end);
        if (!CollectionUtils.isEmpty(request.getClerkIds())) {
            log.setClerkIds(JSON.toJSONString(request.getClerkIds()));
        }
        log.setDryRun(dryRun);
        log.setOrdersChecked(ordersChecked);
        log.setCreatedCount(createdCount);
        log.setSkippedExisting(skippedExisting);
        log.setWarningCount(warnings.size());
        if (!warnings.isEmpty()) {
            log.setWarnings(JSON.toJSONString(warnings));
        }
        log.setComment(request.getComment());
        log.setCreatedBy(log.getOperatorId());
        log.setUpdatedBy(log.getOperatorId());
        backfillLogService.save(log);
        response.setLogId(log.getId());
        return response;
    }

    private boolean hasExistingEarnings(String tenantId, String orderId) {
        Long count = earningsService.lambdaQuery()
                .eq(EarningsLineEntity::getTenantId, tenantId)
                .eq(EarningsLineEntity::getOrderId, orderId)
                .count();
        return count != null && count > 0;
    }

    private BigDecimal resolveAmount(PlayOrderInfoEntity order, List<String> warnings) {
        if (order == null) {
            return null;
        }
        if (order.getAcceptBy() == null) {
            addWarning(warnings, "订单 " + order.getId() + " 无接单人，跳过");
            return null;
        }
        BigDecimal amount = order.getEstimatedRevenue() != null ? order.getEstimatedRevenue()
                : (order.getOrderMoney() != null ? order.getOrderMoney() : BigDecimal.ZERO);
        if (amount.compareTo(BigDecimal.ZERO) < 0) {
            addWarning(warnings, "订单 " + order.getId() + " 收益金额为负数，跳过");
            return null;
        }
        if (order.getOrderEndTime() == null) {
            addWarning(warnings, "订单 " + order.getId() + " 缺少结束时间，跳过");
            return null;
        }
        return amount;
    }

    private void addWarning(List<String> warnings, String message) {
        if (warnings.size() >= 50) {
            return;
        }
        warnings.add(message);
    }

    private LocalDateTime parseDate(String value) {
        if (value == null || value.trim().isEmpty()) {
            return null;
        }
        String trimmed = value.trim();
        List<DateTimeFormatter> formatters = new ArrayList<>();
        formatters.add(ISO_DATE_TIME);
        formatters.add(SIMPLE_DATE_TIME);
        for (DateTimeFormatter formatter : formatters) {
            try {
                return LocalDateTime.parse(trimmed, formatter);
            } catch (DateTimeParseException ignored) {
            }
        }
        throw new CustomException("无法解析时间：" + value);
    }

    private interface SupplierWithException<T> {
        T get() throws Exception;
    }

    private String safe(SupplierWithException<String> supplier) {
        try {
            return supplier.get();
        } catch (Exception ignored) {
            return null;
        }
    }
}
