package com.zsElectric.boot.system.controller;

import cn.idev.excel.EasyExcel;
import com.zsElectric.boot.common.annotation.Log;
import com.zsElectric.boot.common.enums.LogModuleEnum;
import com.zsElectric.boot.core.web.Result;
import com.zsElectric.boot.system.model.dto.ChurnUserExportDTO;
import com.zsElectric.boot.system.model.query.HistoryBusinessQuery;
import com.zsElectric.boot.system.model.query.StationRankQuery;
import com.zsElectric.boot.system.model.vo.*;
import com.zsElectric.boot.system.service.DataBoardService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springdoc.core.annotations.ParameterObject;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.List;

/**
 * 数据看板控制器
 * <p>
 * 提供首页数据看板的各项统计数据接口，包括：
 * <ul>
 *     <li>实时数据：累计总数据和今日数据</li>
 *     <li>充电度数时段对比趋势：今日与对比日的24小时充电度数对比</li>
 *     <li>历史营业数据：按日/月维度展示充电度数、金额、订单、用户趋势</li>
 *     <li>电站充电数据：热门充电站排名和波动排名</li>
 *     <li>用户流失率：近7天、近1月、近3月的用户流失率统计</li>
 * </ul>
 * </p>
 * <p>
 * 数据格式规范：
 * <ul>
 *     <li>金额、度数等数值保留2位小数</li>
 *     <li>充电金额、充电度数的统计日切时间以订单完成时间为准</li>
 * </ul>
 * </p>
 *
 * @author zsElectric
 * @since 2026-03-09
 */
@Slf4j
@RestController
@RequiredArgsConstructor
@Tag(name = "数据看板")
@RequestMapping("/api/v1/dataBoard")
public class DataBoardController {

    private final DataBoardService dataBoardService;

    // ==================== 实时数据模块 ====================

    /**
     * 获取实时数据（累计总数据）
     * <p>
     * 包含字段：总充电度数、总充电金额、总抵扣券购买金额、总服务费金额、总退款金额、
     * 总实付金额、总首单立减、总优惠券减免、总企业专享价减、总分销佣金
     * </p>
     */
    @Operation(summary = "获取实时数据（累计总数据）",
            description = "获取平台累计的各项统计数据，包括充电度数、金额、退款、佣金等")
    @GetMapping("/realTimeData")
    @Log(value = "获取实时数据", module = LogModuleEnum.OTHER)
    public Result<DataBoardRealTimeVO> getRealTimeData() {
        DataBoardRealTimeVO data = dataBoardService.getRealTimeData();
        return Result.success(data);
    }

    /**
     * 获取今日实时数据
     * <p>
     * 包含字段：今日充电度数、今日充电金额、今日抵扣券购买金额、今日服务费金额、今日退款金额、
     * 今日实付金额、今日首单立减、今日优惠券减免、今日企业专享价减、今日佣金
     * </p>
     */
    @Operation(summary = "获取今日实时数据",
            description = "获取今日的各项统计数据，数据会实时更新")
    @GetMapping("/todayData")
    @Log(value = "获取今日实时数据", module = LogModuleEnum.OTHER)
    public Result<DataBoardTodayVO> getTodayData() {
        DataBoardTodayVO data = dataBoardService.getTodayData();
        return Result.success(data);
    }

    // ==================== 充电度数时段对比趋势模块 ====================

    /**
     * 获取充电度数时段对比趋势
     * <p>
     * 返回今日与对比日的24小时充电度数数据，用于绘制时段对比趋势图。
     * 横坐标为24小时（0-23），纵坐标为充电度数。
     * </p>
     *
     * @param compareDate 对比日期，格式：MM-dd，可选范围：近15日（昨天之前的15天，含昨天），不传则默认昨天
     */
    @Operation(summary = "获取充电度数时段对比趋势",
            description = "获取今日与对比日的24小时充电度数对比数据，用于绘制日时段对比趋势图")
    @GetMapping("/chargePowerTrend")
    @Log(value = "获取充电度数时段趋势", module = LogModuleEnum.OTHER)
    public Result<ChargePowerTrendVO> getChargePowerTrend(
            @Parameter(description = "对比日期（格式：yyyy-MM-dd）") @RequestParam(required = false) String compareDate) {
        ChargePowerTrendVO data = dataBoardService.getChargePowerTrend(compareDate);
        return Result.success(data);
    }

    // ==================== 历史营业数据模块 ====================

    /**
     * 获取历史营业数据
     * <p>
     * 支持按日趋势或月趋势查询，数据类型包括：充电度数、充电金额、有效订单、注册用户。
     * </p>
     * <ul>
     *     <li>日趋势：yearMonth 格式为 yyyy-MM，查询该月每日数据</li>
     *     <li>月趋势：yearMonth 格式为 yyyy，查询该年每月汇总数据</li>
     * </ul>
     *
     * @param query 查询参数，包含：timeDimension（时间维度）、dataType（数据类型）、yearMonth（时间参数，必传）
     */
    @Operation(summary = "获取历史营业数据",
            description = "获取历史营业趋势数据。日趋势时yearMonth传yyyy-MM查询该月每日数据；月趋势时yearMonth传yyyy查询该年每月汇总数据")
    @GetMapping("/historyBusinessData")
    @Log(value = "获取历史营业数据", module = LogModuleEnum.OTHER)
    public Result<HistoryBusinessDataVO> getHistoryBusinessData(@ParameterObject HistoryBusinessQuery query) {
        HistoryBusinessDataVO data = dataBoardService.getHistoryBusinessData(query);
        return Result.success(data);
    }

    // ==================== 电站充电数据模块 ====================

    /**
     * 获取站点排名数据
     * <p>
     * 返回热门充电站排名（按充电度数排序）和波动充电站排名（按度数波动百分比排序）。
     * 波动计算方式：(当前周期 - 上一周期) / 上一周期 * 100%
     * </p>
     *
     * @param query 查询参数，包含：timeRange（时间范围）、startDate（开始日期）、endDate（结束日期）
     */
    @Operation(summary = "获取站点排名数据",
            description = "获取电站充电数据排名，包括热门充电站排名和波动充电站排名")
    @GetMapping("/stationRankData")
    @Log(value = "获取站点排名数据", module = LogModuleEnum.OTHER)
    public Result<StationRankListVO> getStationRankData(@ParameterObject StationRankQuery query) {
        StationRankListVO data = dataBoardService.getStationRankData(query);
        return Result.success(data);
    }

    // ==================== 用户流失率模块 ====================

    /**
     * 获取用户流失率
     * <p>
     * 返回近7天、近1个月、近3个月的用户流失率。
     * 计算公式：(某期间活跃但后续未活跃的用户数 / 该期间活跃用户数) * 100%
     * </p>
     */
    @Operation(summary = "获取用户流失率",
            description = "获取近7天、近1个月、近3个月的用户流失率统计")
    @GetMapping("/userChurnRate")
    @Log(value = "获取用户流失率", module = LogModuleEnum.OTHER)
    public Result<UserChurnRateVO> getUserChurnRate() {
        UserChurnRateVO data = dataBoardService.getUserChurnRate();
        return Result.success(data);
    }

    /**
     * 导出流失用户列表
     * <p>
     * 导出指定时段的流失用户，包含用户个人信息和最后一次充电信息。
     * </p>
     *
     * @param periodType 时段类型：7d-近7天，1m-近1个月，3m-近3个月
     */
    @Operation(summary = "导出流失用户列表",
            description = "导出流失用户的个人信息和最后一次充电信息")
    @GetMapping("/churnUsers/export")
    @Log(value = "导出流失用户", module = LogModuleEnum.OTHER)
    public void exportChurnUsers(
            @Parameter(description = "时段类型：7d-近7天，1m-近1个月，3m-近3个月", example = "1m")
            @RequestParam(defaultValue = "1m") String periodType,
            HttpServletResponse response) throws IOException {

        String periodName = switch (periodType) {
            case "7d" -> "近7天";
            case "3m" -> "近3个月";
            default -> "近1个月";
        };
        String fileName = periodName + "用户流失情况表.xlsx";

        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(fileName, StandardCharsets.UTF_8));

        List<ChurnUserExportDTO> exportList = dataBoardService.getChurnUserExportList(periodType);
        EasyExcel.write(response.getOutputStream(), ChurnUserExportDTO.class)
                .sheet(periodName + " 用户流失情况表")
                .doWrite(exportList);
    }
}
