package com.haha.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.haha.common.constant.DeviceConstants;
import com.haha.common.constant.OrderConstants;
import com.haha.common.enums.CommonStatus;
import com.haha.entity.Device;
import com.haha.entity.Order;
import com.haha.entity.Shop;
import com.haha.entity.User;
import com.haha.mapper.DeviceInventoryMapper;
import com.haha.service.*;
import com.haha.service.DeviceAlertService;
import com.haha.service.ShopService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * 首页数据看板服务实现类
 */
@Slf4j
@Service
public class DashboardServiceImpl implements DashboardService {

    @Autowired
    private OrderService orderService;

    @Autowired
    private DeviceService deviceService;

    @Autowired
    private UserService userService;

    @Autowired
    private DeviceInventoryMapper deviceInventoryMapper;

    @Autowired
    private DeviceAlertService deviceAlertService;

    @Autowired
    private ShopService shopService;

    /** 执行 COUNT + SUM 聚合查询，返回一行两列。需用 QueryWrapper 支持原始 SQL */
    private Map<String, Object> aggOrders(QueryWrapper<Order> wrapper) {
        wrapper.select("IFNULL(COUNT(*), 0) as cnt", "IFNULL(SUM(total_amount), 0) as sum");
        List<Map<String, Object>> list = orderService.getBaseMapper().selectMaps(wrapper);
        return list != null && !list.isEmpty() ? list.get(0) : Map.of("cnt", 0L, "sum", BigDecimal.ZERO);
    }

    @Override
    public Map<String, Object> getOverviewData() {
        Map<String, Object> result = new HashMap<>();

        LocalDateTime todayStart = LocalDateTime.of(LocalDate.now(), LocalTime.MIN);
        LocalDateTime todayEnd = LocalDateTime.of(LocalDate.now(), LocalTime.MAX);
        LocalDateTime yesterdayStart = todayStart.minusDays(1);
        LocalDateTime yesterdayEnd = LocalDateTime.now().minusDays(1);

        // 今日 — SQL COUNT + SUM，1 行返回
        Map<String, Object> todayStats = aggOrders(new QueryWrapper<Order>()
                .eq("pay_status", OrderConstants.PAY_STATUS_PAID)
                .ge("pay_time", todayStart).le("pay_time", todayEnd));
        BigDecimal todaySales = (BigDecimal) todayStats.get("sum");
        int todayOrderCount = ((Number) todayStats.get("cnt")).intValue();

        result.put("todaySales", todaySales.setScale(2, RoundingMode.HALF_UP).toString());
        result.put("todayOrders", todayOrderCount);
        result.put("todayAvgPrice", todayOrderCount > 0
                ? todaySales.divide(BigDecimal.valueOf(todayOrderCount), 2, RoundingMode.HALF_UP).toString()
                : "0.00");

        // 昨日
        Map<String, Object> yesterdayStats = aggOrders(new QueryWrapper<Order>()
                .eq("pay_status", OrderConstants.PAY_STATUS_PAID)
                .ge("pay_time", yesterdayStart).le("pay_time", yesterdayEnd));
        BigDecimal yesterdaySales = (BigDecimal) yesterdayStats.get("sum");
        int yesterdayOrderCount = ((Number) yesterdayStats.get("cnt")).intValue();
        BigDecimal yesterdayAvgPrice = yesterdayOrderCount > 0
                ? yesterdaySales.divide(BigDecimal.valueOf(yesterdayOrderCount), 2, RoundingMode.HALF_UP)
                : BigDecimal.ZERO;

        result.put("todaySalesCompare", formatCompare(todaySales.subtract(yesterdaySales)));
        result.put("todayOrdersCompare", formatCompare(todayOrderCount - yesterdayOrderCount));
        result.put("todayAvgPriceCompare", formatCompare(todayOrderCount > 0
                ? todaySales.divide(BigDecimal.valueOf(todayOrderCount), 2, RoundingMode.HALF_UP) : BigDecimal.ZERO
                .subtract(yesterdayAvgPrice)));

        long totalDevices = deviceService.count();
        long onlineDevices = deviceService.lambdaQuery()
                .eq(Device::getStatus, DeviceConstants.STATUS_ONLINE).count();
        result.put("onlineDevices", onlineDevices);
        result.put("offlineDevices", totalDevices - onlineDevices);

        long unpaidOrders = orderService.lambdaQuery()
                .eq(Order::getStatus, OrderConstants.STATUS_PENDING_PAYMENT).count();
        result.put("unpaidOrders", unpaidOrders);
        result.put("pendingTasks", (int) unpaidOrders);
        result.put("abnormalActivities", 0);
        result.put("pendingAfterSale", 0);

        long totalUsers = userService.count();
        result.put("totalUsers", totalUsers);
        long todayNewUsers = userService.lambdaQuery()
                .ge(User::getCreateTime, todayStart).le(User::getCreateTime, todayEnd).count();
        result.put("todayNewUsers", todayNewUsers);

        long totalOrders = orderService.lambdaQuery()
                .eq(Order::getPayStatus, OrderConstants.PAY_STATUS_PAID).count();
        result.put("totalOrders", totalOrders);
        // 总收入 — SQL SUM，1 行返回（不再加载所有历史订单）
        Map<String, Object> allPaidStats = aggOrders(new QueryWrapper<Order>()
                .eq("pay_status", OrderConstants.PAY_STATUS_PAID));
        result.put("totalRevenue", ((BigDecimal) allPaidStats.get("sum")).setScale(2, RoundingMode.HALF_UP).toString());
        result.put("todayRevenue", todaySales.setScale(2, RoundingMode.HALF_UP).toString());
        result.put("totalDevices", totalDevices);

        long totalShops = shopService.count();
        long activeShops = shopService.lambdaQuery()
                .eq(Shop::getStatus, CommonStatus.ENABLED.getCode()).count();
        result.put("totalShops", totalShops);
        result.put("activeShops", activeShops);

        LocalDateTime monthStart = LocalDateTime.of(LocalDate.now().withDayOfMonth(1), LocalTime.MIN);
        Map<String, Object> monthStats = aggOrders(new QueryWrapper<Order>()
                .eq("pay_status", OrderConstants.PAY_STATUS_PAID)
                .ge("pay_time", monthStart).le("pay_time", LocalDateTime.now()));
        result.put("monthSales", ((BigDecimal) monthStats.get("sum")).setScale(2, RoundingMode.HALF_UP).toString());
        result.put("monthOrders", ((Number) monthStats.get("cnt")).intValue());

        return result;
    }

    @Override
    public Map<String, Object> getStatisticsData(String type) {
        Map<String, Object> result = new HashMap<>();

        // 计算时间范围
        LocalDateTime startTime;
        LocalDateTime endTime = LocalDateTime.now();
        LocalDateTime compareStartTime;
        LocalDateTime compareEndTime;

        int days;
        switch (type) {
            case "yesterday":
                startTime = LocalDateTime.of(LocalDate.now().minusDays(1), LocalTime.MIN);
                endTime = LocalDateTime.of(LocalDate.now().minusDays(1), LocalTime.MAX);
                compareStartTime = startTime.minusDays(1);
                compareEndTime = endTime.minusDays(1);
                days = 1;
                break;
            case "month":
                startTime = LocalDateTime.of(LocalDate.now().withDayOfMonth(1), LocalTime.MIN);
                compareStartTime = startTime.minusMonths(1);
                compareEndTime = startTime.minusDays(1);
                days = LocalDate.now().getDayOfMonth();
                break;
            case "days30":
                startTime = LocalDateTime.now().minusDays(30);
                compareStartTime = startTime.minusDays(30);
                compareEndTime = startTime.minusDays(1);
                days = 30;
                break;
            case "week":
            default:
                startTime = LocalDateTime.now().minusDays(7);
                compareStartTime = startTime.minusDays(7);
                compareEndTime = startTime.minusDays(1);
                days = 7;
                break;
        }

        // 查询订单 — 只取需要的字段，不拉全部列
        LambdaQueryWrapper<Order> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Order::getPayStatus, OrderConstants.PAY_STATUS_PAID)
               .ge(Order::getPayTime, startTime)
               .le(Order::getPayTime, endTime)
               .select(Order::getPayTime, Order::getTotalAmount, Order::getUserId);
        List<Order> orders = orderService.list(wrapper);

        BigDecimal totalSales = orders.stream()
                .map(o -> o.getTotalAmount() != null ? o.getTotalAmount() : BigDecimal.ZERO)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        result.put("totalSales", totalSales.setScale(2, RoundingMode.HALF_UP).toString());
        int totalOrders = orders.size();
        result.put("totalOrders", totalOrders);
        result.put("avgOrderPrice", totalOrders > 0
                ? totalSales.divide(BigDecimal.valueOf(totalOrders), 2, RoundingMode.HALF_UP).toString()
                : "0.00");

        // 对比期 — 同样只取需要的字段
        LambdaQueryWrapper<Order> compareWrapper = new LambdaQueryWrapper<>();
        compareWrapper.eq(Order::getPayStatus, OrderConstants.PAY_STATUS_PAID)
                      .ge(Order::getPayTime, compareStartTime)
                      .le(Order::getPayTime, compareEndTime)
                      .select(Order::getPayTime, Order::getTotalAmount, Order::getUserId);
        List<Order> compareOrders = orderService.list(compareWrapper);
        BigDecimal compareSales = compareOrders.stream()
                .map(o -> o.getTotalAmount() != null ? o.getTotalAmount() : BigDecimal.ZERO)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        int compareOrderCount = compareOrders.size();
        BigDecimal compareAvgPrice = compareOrderCount > 0
                ? compareSales.divide(BigDecimal.valueOf(compareOrderCount), 2, RoundingMode.HALF_UP)
                : BigDecimal.ZERO;

        BigDecimal avgOrderPrice = totalOrders > 0
                ? totalSales.divide(BigDecimal.valueOf(totalOrders), 2, RoundingMode.HALF_UP) : BigDecimal.ZERO;
        result.put("salesGrowth", formatGrowth(totalSales, compareSales));
        result.put("ordersGrowth", formatGrowth(totalOrders, compareOrderCount));
        result.put("avgOrderGrowth", formatGrowth(avgOrderPrice, compareAvgPrice));

        BigDecimal grossProfit = totalSales.multiply(new BigDecimal("0.3"));
        BigDecimal profitMargin = totalSales.compareTo(BigDecimal.ZERO) > 0
                ? grossProfit.divide(totalSales, 4, RoundingMode.HALF_UP).multiply(new BigDecimal("100"))
                : BigDecimal.ZERO;
        BigDecimal compareGrossProfit = compareSales.multiply(new BigDecimal("0.3"));
        result.put("grossProfit", grossProfit.setScale(2, RoundingMode.HALF_UP).toString());
        result.put("profitMargin", profitMargin.setScale(1, RoundingMode.HALF_UP).toString() + "%");
        result.put("profitGrowth", formatGrowth(grossProfit, compareGrossProfit));
        result.put("marginGrowth", "+0%");

        // 用户统计
        long newUsers = userService.lambdaQuery()
                .ge(User::getCreateTime, startTime).le(User::getCreateTime, endTime).count();
        result.put("newUsers", newUsers);

        Set<Long> transactUserIds = new HashSet<>();
        for (Order order : orders) { if (order.getUserId() != null) transactUserIds.add(order.getUserId()); }
        result.put("transactUsers", transactUserIds.size());
        result.put("customerPrice", transactUserIds.size() > 0
                ? totalSales.divide(BigDecimal.valueOf(transactUserIds.size()), 2, RoundingMode.HALF_UP).toString()
                : "0.00");

        long compareNewUsers = userService.lambdaQuery()
                .ge(User::getCreateTime, compareStartTime).le(User::getCreateTime, compareEndTime).count();
        Set<Long> compareTransactUserIds = new HashSet<>();
        for (Order order : compareOrders) { if (order.getUserId() != null) compareTransactUserIds.add(order.getUserId()); }
        BigDecimal compareCustomerPrice = compareTransactUserIds.size() > 0
                ? compareSales.divide(BigDecimal.valueOf(compareTransactUserIds.size()), 2, RoundingMode.HALF_UP)
                : BigDecimal.ZERO;

        BigDecimal customerPrice = transactUserIds.size() > 0
                ? totalSales.divide(BigDecimal.valueOf(transactUserIds.size()), 2, RoundingMode.HALF_UP) : BigDecimal.ZERO;
        result.put("newUsersGrowth", formatGrowth(newUsers, compareNewUsers));
        result.put("transactGrowth", formatGrowth(transactUserIds.size(), compareTransactUserIds.size()));
        result.put("customerGrowth", formatGrowth(customerPrice, compareCustomerPrice));

        // 按时间分组：一次遍历，按天/小时聚合销售额和订单数
        Map<String, BigDecimal> dateSalesMap = new LinkedHashMap<>();
        Map<String, Integer> dateOrdersMap = new LinkedHashMap<>();
        if ("yesterday".equals(type)) {
            for (int i = 0; i < 24; i++) {
                String key = i + ":00";
                dateSalesMap.put(key, BigDecimal.ZERO);
                dateOrdersMap.put(key, 0);
            }
            for (Order o : orders) {
                if (o.getPayTime() != null) {
                    String key = o.getPayTime().getHour() + ":00";
                    dateSalesMap.merge(key, o.getTotalAmount() != null ? o.getTotalAmount() : BigDecimal.ZERO, BigDecimal::add);
                    dateOrdersMap.merge(key, 1, Integer::sum);
                }
            }
        } else {
            for (int i = 0; i < days; i++) {
                LocalDate date = startTime.toLocalDate().plusDays(i);
                String key = date.format(DateTimeFormatter.ofPattern("MM-dd"));
                dateSalesMap.put(key, BigDecimal.ZERO);
                dateOrdersMap.put(key, 0);
            }
            for (Order o : orders) {
                if (o.getPayTime() != null) {
                    String key = o.getPayTime().toLocalDate().format(DateTimeFormatter.ofPattern("MM-dd"));
                    dateSalesMap.merge(key, o.getTotalAmount() != null ? o.getTotalAmount() : BigDecimal.ZERO, BigDecimal::add);
                    dateOrdersMap.merge(key, 1, Integer::sum);
                }
            }
        }
        result.put("dates", new ArrayList<>(dateSalesMap.keySet()));
        result.put("salesData", new ArrayList<>(dateSalesMap.values()));
        result.put("ordersData", new ArrayList<>(dateOrdersMap.values()));

        return result;
    }

    @Override
    public Map<String, Object> getQuickLinksData() {
        Map<String, Object> result = new HashMap<>();

        // 设备不在线数
        long offlineDevices = deviceService.lambdaQuery()
                .ne(Device::getStatus, DeviceConstants.STATUS_ONLINE)
                .count();
        result.put("offlineDevices", offlineDevices);

        // 未支付订单数
        long unpaidOrders = orderService.lambdaQuery()
                .eq(Order::getStatus, OrderConstants.STATUS_PENDING_PAYMENT)
                .count();
        result.put("unpaidOrders", unpaidOrders);

        // 需补货设备数（库存低于预警阈值）
        try {
            List<Map<String, Object>> lowStockList = deviceInventoryMapper.selectLowStockInventories();
            Set<String> needRestockDevices = new HashSet<>();
            for (Map<String, Object> item : lowStockList) {
                Object deviceId = item.get("device_id");
                if (deviceId != null) {
                    needRestockDevices.add(deviceId.toString());
                }
            }
            result.put("needRestock", needRestockDevices.size());
        } catch (Exception e) {
            result.put("needRestock", 0);
        }

        // 其他待处理项（暂返回0，待后续实现）
        result.put("unknownProducts", 0);   // 未知商品设备数
        result.put("pendingAfterSale", 0);  // 售后待审核数
        result.put("abnormalActivities", 0); // 异常待处理数
        result.put("complaints", 0);         // 投诉建议数
        
        // 待办事项相关数据
        // 待处理退款数（售后待审核）
        result.put("pendingRefunds", 0); // TODO: 后续实现售后模块后从售后表查询
        
        // 设备异常告警数（未处理的告警记录）
        try {
            long pendingAlerts = deviceAlertService.lambdaQuery()
                    .eq(com.haha.entity.DeviceAlertRecord::getNotifyStatus, 0) // 0-未发送/未处理
                    .count();
            result.put("pendingAlerts", pendingAlerts);
        } catch (Exception e) {
            log.warn("查询设备告警数失败", e);
            result.put("pendingAlerts", 0);
        }
        
        // 未支付订单数（已经在上面计算过）
        // result.put("unpaidOrders", unpaidOrders);
        
        // 待补货数（低库存SKU数量）
        try {
            List<Map<String, Object>> lowStockList = deviceInventoryMapper.selectLowStockInventories();
            result.put("lowStockItems", lowStockList.size());
        } catch (Exception e) {
            result.put("lowStockItems", 0);
        }
        
        // 待开发票数
        result.put("pendingInvoices", 0); // TODO: 后续实现发票模块后从发票表查询
        
        // 临期商品在售数
        result.put("expiringProducts", 0); // TODO: 后续实现商品效期管理后查询
        result.put("skuSuggestions", 0);     // SKU建议数

        return result;
    }

    @Override
    public Object getDeviceStatusData() {
        List<Map<String, Object>> result = new ArrayList<>();

        long onlineDevices = deviceService.lambdaQuery()
                .eq(Device::getStatus, DeviceConstants.STATUS_ONLINE)
                .count();
        long totalDevices = deviceService.count();
        long offlineDevices = totalDevices - onlineDevices;

        Map<String, Object> online = new HashMap<>();
        online.put("name", "在线");
        online.put("value", onlineDevices);
        online.put("color", "#67C23A");
        result.add(online);

        Map<String, Object> offline = new HashMap<>();
        offline.put("name", "不在线");
        offline.put("value", offlineDevices);
        offline.put("color", "#909399");
        result.add(offline);

        return result;
    }

    /**
     * 格式化对比数值（正负号）
     */
    private String formatCompare(BigDecimal value) {
        if (value.compareTo(BigDecimal.ZERO) > 0) {
            return "+" + value.setScale(2, RoundingMode.HALF_UP).toString();
        } else if (value.compareTo(BigDecimal.ZERO) < 0) {
            return value.setScale(2, RoundingMode.HALF_UP).toString();
        }
        return "+0.00";
    }

    /**
     * 格式化对比数值（整数）
     */
    private String formatCompare(int value) {
        if (value > 0) {
            return "+" + value;
        } else if (value < 0) {
            return String.valueOf(value);
        }
        return "+0";
    }

    /**
     * 格式化增长率
     */
    private String formatGrowth(BigDecimal current, BigDecimal previous) {
        if (previous.compareTo(BigDecimal.ZERO) == 0) {
            return current.compareTo(BigDecimal.ZERO) > 0 ? "+100%" : "+0%";
        }
        BigDecimal growth = current.subtract(previous)
                .divide(previous, 4, RoundingMode.HALF_UP)
                .multiply(new BigDecimal("100"));
        if (growth.compareTo(BigDecimal.ZERO) > 0) {
            return "+" + growth.setScale(1, RoundingMode.HALF_UP) + "%";
        } else if (growth.compareTo(BigDecimal.ZERO) < 0) {
            return growth.setScale(1, RoundingMode.HALF_UP) + "%";
        }
        return "+0%";
    }

    /**
     * 格式化增长率（整数）
     */
    private String formatGrowth(long current, long previous) {
        if (previous == 0) {
            return current > 0 ? "+100%" : "+0%";
        }
        double growth = ((double)(current - previous) / previous) * 100;
        if (growth > 0) {
            return "+" + String.format("%.0f", growth) + "%";
        } else if (growth < 0) {
            return String.format("%.0f", growth) + "%";
        }
        return "+0%";
    }
}
