package com.erp.dashboard.service.impl;

import com.erp.common.core.exception.BusinessException;
import com.erp.dashboard.dto.*;
import com.erp.dashboard.repository.*;
import com.erp.dashboard.service.DashboardService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.List;

/**
 * Dashboard服务实现类
 * 
 * 功能：
 * 1. 仪表盘概览数据（本月订单统计、本月API调用统计）
 * 2. 配额使用情况（订单配额、API配额）
 * 3. 云仓成功率统计
 * 4. 预警信息（库存预警、订单配额预警、API配额预警、云仓推送异常）
 * 5. 近期订单列表
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class DashboardServiceImpl implements DashboardService {

    private final OrderRepository orderRepository;
    private final PullRecordRepository pullRecordRepository;
    private final StockRepository stockRepository;
    private final SystemConfigRepository systemConfigRepository;

    @Lazy
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    // 默认近7天
    private static final int DEFAULT_RECENT_DAYS = 7;
    // 预警阈值百分比
    private static final int WARNING_PERCENT = 80;
    private static final int CRITICAL_PERCENT = 100;

    @Override
    @Transactional(readOnly = true)
    public DashboardResponse getDashboardData(Long tenantId, Integer recentDays) {
        if (tenantId == null) {
            throw new BusinessException(400, "租户ID不能为空");
        }

        int days = recentDays != null ? recentDays : DEFAULT_RECENT_DAYS;
        if (days < 1 || days > 90) {
            throw new BusinessException(400, "recent_days必须在1-90之间");
        }

        LocalDate today = LocalDate.now();
        LocalDate monthStart = today.withDayOfMonth(1);
        LocalDate monthEnd = today.withDayOfMonth(today.lengthOfMonth());
        LocalDate recentStart = today.minusDays(days);

        // ── 1. 本月订单统计 ───────────────────────────────────────
        OrderStatsDTO monthOrderStats = orderRepository.selectMonthOrderStats(
                tenantId,
                monthStart.atStartOfDay(),
                monthEnd.atTime(LocalTime.MAX)
        );

        // ── 2. 本月API调用统计 ────────────────────────────────────
        ApiStatsDTO monthApiStats = pullRecordRepository.selectMonthApiStats(
                monthStart.atStartOfDay(),
                monthEnd.atTime(LocalTime.MAX)
        );

        // ── 3. 订单配额 ────────────────────────────────────────────
        OrderQuotaDTO orderQuota = buildOrderQuota(tenantId, monthStart, monthEnd, monthOrderStats);

        // ── 4. API调用配额 ────────────────────────────────────────
        ApiQuotaDTO apiQuota = buildApiQuota(today);

        // ── 5. 云仓成功率 ─────────────────────────────────────────
        CloudWarehouseStatsDTO cloudWarehouse = buildCloudWarehouse(tenantId, monthStart, monthEnd);

        // ── 6. 预警信息 ──────────────────────────────────────────
        List<AlertDTO> alerts = buildAlerts(tenantId, monthStart, monthEnd, today);

        // ── 7. 近期订单列表 ─────────────────────────────────────
        List<RecentOrderDTO> recentOrders = orderRepository.selectRecentOrders(
                tenantId,
                recentStart.atStartOfDay(),
                today.atTime(LocalTime.MAX),
                20
        );

        // ── 组装响应 ─────────────────────────────────────────────
        DashboardResponse.Summary summary = DashboardResponse.Summary.builder()
                .monthOrders(buildMonthOrders(monthOrderStats))
                .monthApiCalls(buildMonthApiCalls(monthApiStats))
                .orderQuota(orderQuota)
                .apiQuota(apiQuota)
                .cloudWarehouse(cloudWarehouse)
                .build();

        DashboardResponse.DashboardData data = DashboardResponse.DashboardData.builder()
                .summary(summary)
                .alerts(alerts)
                .recentOrders(recentOrders)
                .build();

        return DashboardResponse.builder()
                .code(200)
                .message("success")
                .data(data)
                .build();
    }

    /**
     * 构建本月订单统计
     */
    private MonthOrdersDTO buildMonthOrders(OrderStatsDTO stats) {
        return MonthOrdersDTO.builder()
                .total(stats.getTotalOrders() != null ? stats.getTotalOrders().intValue() : 0)
                .completed(stats.getCompletedOrders() != null ? stats.getCompletedOrders().intValue() : 0)
                .cancelled(stats.getCancelledOrders() != null ? stats.getCancelledOrders().intValue() : 0)
                .amount(stats.getTotalAmount() != null ? stats.getTotalAmount() : BigDecimal.ZERO)
                .build();
    }

    /**
     * 构建本月API调用统计
     */
    private MonthApiCallsDTO buildMonthApiCalls(ApiStatsDTO stats) {
        int total = stats.getTotalCalls() != null ? stats.getTotalCalls().intValue() : 0;
        int success = stats.getSuccessCalls() != null ? stats.getSuccessCalls().intValue() : 0;

        return MonthApiCallsDTO.builder()
                .total(total)
                .success(success)
                .failed(stats.getFailedCalls() != null ? stats.getFailedCalls().intValue() : 0)
                .ordersPulled(stats.getTotalOrdersPulled() != null ? stats.getTotalOrdersPulled().intValue() : 0)
                .successRate(calculateRate(total, success))
                .build();
    }

    /**
     * 构建订单配额
     */
    private OrderQuotaDTO buildOrderQuota(Long tenantId, LocalDate monthStart, LocalDate monthEnd, 
                                          OrderStatsDTO monthOrderStats) {
        String limitStr = systemConfigRepository.getValue("tenant_quota", "monthly_order_limit");
        int limit = limitStr != null ? Integer.parseInt(limitStr) : 0;
        int used = monthOrderStats.getTotalOrders() != null ? monthOrderStats.getTotalOrders().intValue() : 0;

        if (limit <= 0) {
            return OrderQuotaDTO.builder()
                    .limit(limit)
                    .used(used)
                    .remain(null)
                    .percent(null)
                    .build();
        }

        int remain = Math.max(0, limit - used);
        BigDecimal percent = BigDecimal.valueOf(used)
                .multiply(BigDecimal.valueOf(100))
                .divide(BigDecimal.valueOf(limit), 2, RoundingMode.HALF_UP);

        return OrderQuotaDTO.builder()
                .limit(limit)
                .used(used)
                .remain(remain)
                .percent(percent)
                .build();
    }

    /**
     * 构建API配额
     */
    private ApiQuotaDTO buildApiQuota(LocalDate today) {
        String limitStr = systemConfigRepository.getValue("tenant_quota", "daily_api_limit");
        int dailyLimit = limitStr != null ? Integer.parseInt(limitStr) : 0;
        
        long todayUsed = pullRecordRepository.countTodayApiCalls(
                today.atStartOfDay(),
                today.atTime(LocalTime.MAX)
        );

        if (dailyLimit <= 0) {
            return ApiQuotaDTO.builder()
                    .dailyLimit(dailyLimit)
                    .todayUsed((int) todayUsed)
                    .dailyRemain(null)
                    .dailyPercent(null)
                    .build();
        }

        int dailyRemain = Math.max(0, dailyLimit - (int) todayUsed);
        BigDecimal dailyPercent = BigDecimal.valueOf(todayUsed)
                .multiply(BigDecimal.valueOf(100))
                .divide(BigDecimal.valueOf(dailyLimit), 2, RoundingMode.HALF_UP);

        return ApiQuotaDTO.builder()
                .dailyLimit(dailyLimit)
                .todayUsed((int) todayUsed)
                .dailyRemain(dailyRemain)
                .dailyPercent(dailyPercent)
                .build();
    }

    /**
     * 构建云仓统计
     */
    private CloudWarehouseStatsDTO buildCloudWarehouse(Long tenantId,
                                                                      LocalDate monthStart,
                                                                      LocalDate monthEnd) {
        CloudWarehouseStatsDTO stats = orderRepository.selectCloudWarehouseStats(
                tenantId,
                monthStart.atStartOfDay(),
                monthEnd.atTime(LocalTime.MAX)
        );

        return stats;
    }

    /**
     * 构建预警信息列表
     */
    private List<AlertDTO> buildAlerts(Long tenantId, LocalDate monthStart, LocalDate monthEnd, LocalDate today) {
        List<AlertDTO> alerts = new ArrayList<>();

        // ── 1. 库存预警 ──────────────────────────────────────────
        String globalThresholdStr = systemConfigRepository.getValue("stock_alert_settings", "global_threshold");
        int globalThreshold = globalThresholdStr != null ? Integer.parseInt(globalThresholdStr) : 10;

        Long criticalStock = stockRepository.countCriticalStock(tenantId, globalThreshold);
        if (criticalStock != null && criticalStock > 0) {
            alerts.add(AlertDTO.builder()
                    .type(AlertDTO.TYPE_STOCK_CRITICAL)
                    .level(AlertDTO.LEVEL_CRITICAL)
                    .title("库存严重不足")
                    .message(String.format("有 %d 个商品库存严重不足（低于预警值的50%）", criticalStock))
                    .count(criticalStock.intValue())
                    .build());
        }

        Long warningStock = stockRepository.countWarningStock(tenantId, globalThreshold);
        if (warningStock != null && warningStock > 0) {
            alerts.add(AlertDTO.builder()
                    .type(AlertDTO.TYPE_STOCK_WARNING)
                    .level(AlertDTO.LEVEL_WARNING)
                    .title("库存预警")
                    .message(String.format("有 %d 个商品库存低于预警阈值", warningStock))
                    .count(warningStock.intValue())
                    .build());
        }

        // ── 2. 订单配额预警 ──────────────────────────────────────
        String orderLimitStr = systemConfigRepository.getValue("tenant_quota", "monthly_order_limit");
        int orderLimit = orderLimitStr != null ? Integer.parseInt(orderLimitStr) : 0;
        
        if (orderLimit > 0) {
            Long monthOrders = orderRepository.countMonthOrders(
                    tenantId,
                    monthStart.atStartOfDay(),
                    monthEnd.atTime(LocalTime.MAX)
            );
            
            int orders = monthOrders != null ? monthOrders.intValue() : 0;
            BigDecimal usagePercent = BigDecimal.valueOf(orders)
                    .multiply(BigDecimal.valueOf(100))
                    .divide(BigDecimal.valueOf(orderLimit), 2, RoundingMode.HALF_UP);

            if (usagePercent.compareTo(BigDecimal.valueOf(CRITICAL_PERCENT)) >= 0) {
                alerts.add(AlertDTO.builder()
                        .type(AlertDTO.TYPE_ORDER_QUOTA_EXCEEDED)
                        .level(AlertDTO.LEVEL_CRITICAL)
                        .title("本月订单额度已用尽")
                        .message(String.format("本月订单量 %d 已达上限 %d", orders, orderLimit))
                        .count(orders)
                        .build());
            } else if (usagePercent.compareTo(BigDecimal.valueOf(WARNING_PERCENT)) >= 0) {
                int remain = Math.max(0, orderLimit - orders);
                alerts.add(AlertDTO.builder()
                        .type(AlertDTO.TYPE_ORDER_QUOTA_WARNING)
                        .level(AlertDTO.LEVEL_WARNING)
                        .title("订单额度即将用尽")
                        .message(String.format("本月订单量已达 %.2f%%，剩余 %d 单", usagePercent, remain))
                        .count(orders)
                        .build());
            }
        }

        // ── 3. API配额预警 ───────────────────────────────────────
        String apiLimitStr = systemConfigRepository.getValue("tenant_quota", "daily_api_limit");
        int apiLimit = apiLimitStr != null ? Integer.parseInt(apiLimitStr) : 0;
        
        if (apiLimit > 0) {
            long todayCalls = pullRecordRepository.countTodayApiCalls(
                    today.atStartOfDay(),
                    today.atTime(LocalTime.MAX)
            );

            int calls = (int) todayCalls;
            BigDecimal usagePercent = BigDecimal.valueOf(calls)
                    .multiply(BigDecimal.valueOf(100))
                    .divide(BigDecimal.valueOf(apiLimit), 2, RoundingMode.HALF_UP);

            if (usagePercent.compareTo(BigDecimal.valueOf(CRITICAL_PERCENT)) >= 0) {
                alerts.add(AlertDTO.builder()
                        .type(AlertDTO.TYPE_API_QUOTA_EXCEEDED)
                        .level(AlertDTO.LEVEL_CRITICAL)
                        .title("今日API额度已用尽")
                        .message(String.format("今日API调用 %d 次已达上限 %d", calls, apiLimit))
                        .count(calls)
                        .build());
            } else if (usagePercent.compareTo(BigDecimal.valueOf(WARNING_PERCENT)) >= 0) {
                int remain = Math.max(0, apiLimit - calls);
                alerts.add(AlertDTO.builder()
                        .type(AlertDTO.TYPE_API_QUOTA_WARNING)
                        .level(AlertDTO.LEVEL_WARNING)
                        .title("API额度即将用尽")
                        .message(String.format("今日API调用已达 %.2f%%，剩余 %d 次", usagePercent, remain))
                        .count(calls)
                        .build());
            }
        }

        // ── 4. 云仓推送异常预警 ─────────────────────────────────
        Long cloudFailed = orderRepository.countCloudFailedOrders(
                tenantId,
                monthStart.atStartOfDay(),
                monthEnd.atTime(LocalTime.MAX)
        );

        if (cloudFailed != null && cloudFailed > 5) {
            alerts.add(AlertDTO.builder()
                    .type(AlertDTO.TYPE_CLOUD_WAREHOUSE_WARNING)
                    .level(AlertDTO.LEVEL_WARNING)
                    .title("云仓推送异常")
                    .message(String.format("本月有 %d 个订单未成功推送至云仓", cloudFailed))
                    .count(cloudFailed.intValue())
                    .build());
        }

        return alerts;
    }

    /**
     * 计算成功率
     */
    @Override
    public BigDecimal calculateRate(int total, int success) {
        if (total <= 0) {
            return null;
        }
        return BigDecimal.valueOf(success)
                .multiply(BigDecimal.valueOf(100))
                .divide(BigDecimal.valueOf(total), 2, RoundingMode.HALF_UP);
    }
}
