package com.pig4cloud.pig.statistics.controller;


import cn.idev.excel.EasyExcel;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.pig4cloud.pig.common.core.exception.BusinessException;
import com.pig4cloud.pig.common.core.util.R;
import com.pig4cloud.pig.statistics.api.dto.user.*;
import com.pig4cloud.pig.statistics.api.vo.user.*;
import com.pig4cloud.pig.statistics.service.UserAnalyseService;
import com.pig4cloud.plugin.excel.annotation.ResponseExcel;
import com.pig4cloud.plugin.excel.annotation.Sheet;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import lombok.AllArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;

import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;


/**
 * @author: lwh
 * @date: 2025-08-06
 * @description: 用户分析
 */
@RestController
@AllArgsConstructor
@RequestMapping("/user")
@Tag(description = "userAnalyse", name = "用户分析")
@SecurityRequirement(name = HttpHeaders.AUTHORIZATION)
public class UserAnalyseController {

	private final UserAnalyseService userAnalyseService;

/***************************************** 新增用户 *****************************************/

	@PostMapping("/new/trend")
	@Operation(summary = "查询新增趋势")
	public R<GetNewUserTrendVO> getNewUserTrend(@Valid @RequestBody UserAnalyseQueryBaseDTO reqDto) {
		GetNewUserTrendVO result = userAnalyseService.getNewUserTrend(reqDto);
		return R.ok(result);
	}

	@PostMapping("/new/detail")
	@Operation(summary = "分页查询新增趋势详情")
	public R<Page<PageNewUserTrendDetailVO>> pageNewUserTrendDetail(@Valid @RequestBody PageUserAnalyseDTO reqDto) {
		Page<PageNewUserTrendDetailVO> result = userAnalyseService.pageNewUserTrendDetail(reqDto);
		return R.ok(result);
	}

	@ResponseExcel(name = "新增趋势详情")
	@PostMapping("/new/trend/export")
	@Operation(summary = "导出新增趋势详情")
	public List<PageNewUserTrendDetailVO> exportNewUserTrend(@Valid @RequestBody UserAnalyseQueryBaseDTO reqDto) {
		// 初始化结果集
		List<PageNewUserTrendDetailVO> allRecords = new ArrayList<>();
		// 分页查询参数
		PageUserAnalyseDTO pageQuery = new PageUserAnalyseDTO();
		BeanUtils.copyProperties(reqDto, pageQuery);
		// 每次查询的批次大小，根据实际内存情况调整
		long batchSize = 1000;
		pageQuery.setSize(batchSize);
		pageQuery.setCurrent(1);

		while (true) {
			// 分批查询数据
			Page<PageNewUserTrendDetailVO> pageResult = userAnalyseService.pageNewUserTrendDetail(pageQuery);
			List<PageNewUserTrendDetailVO> records = pageResult.getRecords();
			if (CollectionUtils.isEmpty(records)) {
				// 没有更多数据，退出循环
				break;
			}
			// 添加到结果集
			allRecords.addAll(records);
			// 如果当前页记录数小于批次大小，说明是最后一页
			if (records.size() < batchSize) {
				break;
			}
			// 准备查询下一页
			pageQuery.setCurrent(pageQuery.getCurrent() + 1);
		}

		return allRecords;
	}

	@PostMapping("/new/retention")
	@Operation(summary = "查询次日留存率")
	public R<GetNewUserRetentionVO> getNewUserRetention(@Valid @RequestBody UserAnalyseQueryBaseDTO reqDto) {
		GetNewUserRetentionVO result = userAnalyseService.getNewUserRetention(reqDto);
		return R.ok(result);
	}
	@PostMapping("/retention/detail")
	@Operation(summary = "分页查询次日留存率详情")
	public R<Page<PageRetentionDetailVO>> pageNewUserRetentionDetail(@Valid @RequestBody PageUserAnalyseDTO reqDto) {
		Page<PageRetentionDetailVO> result = userAnalyseService.pageNewUserRetentionDetail(reqDto);
		return R.ok(result);
	}

	@ResponseExcel(name = "次日留存率详情")
	@PostMapping("/new/retention/export")
	@Operation(summary = "导出次日留存率详情")
	public List<PageRetentionDetailVO> exportNewUserRetention(@Valid @RequestBody UserAnalyseQueryBaseDTO reqDto) {
		// 初始化结果集
		List<PageRetentionDetailVO> allRecords = new ArrayList<>();
		// 分页查询参数
		PageUserAnalyseDTO pageQuery = new PageUserAnalyseDTO();
		BeanUtils.copyProperties(reqDto, pageQuery);
		// 每次查询的批次大小，根据实际内存情况调整
		long batchSize = 1000;
		pageQuery.setSize(batchSize);
		pageQuery.setCurrent(1);

		while (true) {
			// 分批查询数据
			Page<PageRetentionDetailVO> pageResult = userAnalyseService.pageNewUserRetentionDetail(pageQuery);
			List<PageRetentionDetailVO> records = pageResult.getRecords();
			if (CollectionUtils.isEmpty(records)) {
				// 没有更多数据，退出循环
				break;
			}
			// 添加到结果集
			allRecords.addAll(records);
			// 如果当前页记录数小于批次大小，说明是最后一页
			if (records.size() < batchSize) {
				break;
			}
			// 准备查询下一页
			pageQuery.setCurrent(pageQuery.getCurrent() + 1);
		}

		return allRecords;
	}

/***************************************** 活跃用户 *****************************************/

	@PostMapping("/active/trend")
	@Operation(summary = "查询活跃趋势")
	public R<GetNewUserTrendVO> getActiveTrend(@Valid @RequestBody UserAnalyseQueryBaseDTO reqDto) {
		GetNewUserTrendVO result = userAnalyseService.getActiveTrend(reqDto);
		return R.ok(result);
	}

	@PostMapping("/active/compose")
	@Operation(summary = "查询活跃构成")
	public R<GetActiveUserBaseVO> getActiveCompose(@Valid @RequestBody UserAnalyseQueryBaseDTO reqDto) {
		GetActiveUserBaseVO result = userAnalyseService.getActiveCompose(reqDto);
		return R.ok(result);
	}

	@PostMapping("/active/viscosity")
	@Operation(summary = "查询活跃粘度")
	public R<GetActiveUserBaseVO> getActiveViscosity(@Valid @RequestBody UserAnalyseQueryBaseDTO reqDto) {
		GetActiveUserBaseVO result = userAnalyseService.getActiveViscosity(reqDto);
		return R.ok(result);
	}

	@PostMapping("/active/weekrate")
	@Operation(summary = "查询周活跃率")
	public R<GetActiveUserBaseVO> getActiveWeekRate(@Valid @RequestBody UserAnalyseQueryBaseDTO reqDto) {
		GetActiveUserBaseVO result = userAnalyseService.getActiveWeekRate(reqDto);
		return R.ok(result);
	}

	@PostMapping("/active/monthrate")
	@Operation(summary = "查询月活跃率")
	public R<GetActiveUserBaseVO> getActiveMonthRate(@Valid @RequestBody UserAnalyseQueryBaseDTO reqDto) {
		GetActiveUserBaseVO result = userAnalyseService.getActiveMonthRate(reqDto);
		return R.ok(result);
	}

	@PostMapping("/active/detail")
	@Operation(summary = "分页查询活跃详情")
	public R<Page<PageActiveDetailVO>> pageActiveDetail(@Valid @RequestBody PageUserAnalyseDTO reqDto) {
		Page<PageActiveDetailVO> result = userAnalyseService.pageActiveDetail(reqDto);
		return R.ok(result);
	}

	@PostMapping("/active/export")
	@Operation(summary = "导出活跃详情")
	public void exportActiveDetail(@Valid @RequestBody UserAnalyseQueryBaseDTO reqDto, HttpServletResponse response) throws Exception {
		// 1. 根据时间单位确定需要排除的字段
		List<String> excludeFields = new ArrayList<>();
		String timeUnit = reqDto.getTimeUnit();
		switch (timeUnit) {
			case "day":
				excludeFields.add("monthActiveUserRate");
				excludeFields.add("weekActiveUserRate");
				break;
			case "week":
				excludeFields.add("monthActiveUserRate");
				excludeFields.add("mauRate");
				excludeFields.add("wauRate");
				break;
			case "month":
				excludeFields.add("weekActiveUserRate");
				excludeFields.add("mauRate");
				excludeFields.add("wauRate");
				break;
			default:
				// 可根据需要处理默认情况
				break;
		}

		// 2. 分页查询数据（保持原有逻辑）
		List<PageActiveDetailVO> allRecords = new ArrayList<>();
		PageUserAnalyseDTO pageQuery = new PageUserAnalyseDTO();
		BeanUtils.copyProperties(reqDto, pageQuery);
		long batchSize = 1000;
		pageQuery.setSize(batchSize);
		pageQuery.setCurrent(1);

		while (true) {
			Page<PageActiveDetailVO> pageResult = userAnalyseService.pageActiveDetail(pageQuery);
			List<PageActiveDetailVO> records = pageResult.getRecords();
			if (CollectionUtils.isEmpty(records)) {
				break;
			}
			allRecords.addAll(records);
			if (records.size() < batchSize) {
				break;
			}
			pageQuery.setCurrent(pageQuery.getCurrent() + 1);
		}

		// 3. 动态设置Excel响应和导出字段
		response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
		response.setCharacterEncoding("utf-8");
		String fileName = URLEncoder.encode("活跃详情", StandardCharsets.UTF_8).replaceAll("\\+", "%20");
		response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");

		// 使用EasyExcel编程式导出，指定排除字段
		EasyExcel.write(response.getOutputStream(), PageActiveDetailVO.class)
				.excludeColumnFieldNames(excludeFields)
				.sheet("活跃详情")
				.doWrite(allRecords);
	}

/***************************************** 启动次数 *****************************************/
	@PostMapping("/launch/trend")
	@Operation(summary = "查询启动次数趋势")
	public R<GetNewUserTrendVO> getLaunchTrend(@Valid @RequestBody UserAnalyseQueryBaseDTO reqDto) {
		GetNewUserTrendVO result = userAnalyseService.getLaunchTrend(reqDto);
		return R.ok(result);
	}

	@PostMapping("/launch/detail")
	@Operation(summary = "分页查询启动次数详情")
	public R<Page<PageLaunchDetailVO>> pageLaunchDetail(@Valid @RequestBody PageUserAnalyseDTO reqDto) {
		Page<PageLaunchDetailVO> result = userAnalyseService.pageLaunchDetail(reqDto);
		return R.ok(result);
	}

	@ResponseExcel(name = "启动次数详情")
	@PostMapping("/launch/export")
	@Operation(summary = "导出启动次数详情")
	public List<PageLaunchDetailVO> exportLaunchDetail(@Valid @RequestBody UserAnalyseQueryBaseDTO reqDto) {
		// 初始化结果集
		List<PageLaunchDetailVO> allRecords = new ArrayList<>();
		// 分页查询参数
		PageUserAnalyseDTO pageQuery = new PageUserAnalyseDTO();
		BeanUtils.copyProperties(reqDto, pageQuery);
		// 每次查询的批次大小，根据实际内存情况调整
		long batchSize = 1000;
		pageQuery.setSize(batchSize);
		pageQuery.setCurrent(1);

		while (true) {
			// 分批查询数据
			Page<PageLaunchDetailVO> pageResult = userAnalyseService.pageLaunchDetail(pageQuery);
			List<PageLaunchDetailVO> records = pageResult.getRecords();
			if (CollectionUtils.isEmpty(records)) {
				// 没有更多数据，退出循环
				break;
			}
			// 添加到结果集
			allRecords.addAll(records);
			// 如果当前页记录数小于批次大小，说明是最后一页
			if (records.size() < batchSize) {
				break;
			}
			// 准备查询下一页
			pageQuery.setCurrent(pageQuery.getCurrent() + 1);
		}

		return allRecords;
	}

/***************************************** 版本分布 *****************************************/

	@PostMapping("/version/detail")
	@Operation(summary = "分页查询全部版本详情")
	public R<Page<PageAllVersionDetailVO>> pageAllVersionDetail(@Valid @RequestBody PageAllVersionDetailDTO reqDto) {
		Page<PageAllVersionDetailVO> result = userAnalyseService.pageAllVersionDetail(reqDto);
		return R.ok(result);
	}

	@ResponseExcel(name = "全部版本详情", sheets = {
			@Sheet(sheetName = "今日"),
			@Sheet(sheetName = "昨日")
	})
	@GetMapping("/version/export")
	@Operation(summary = "导出全部版本详情")
	public List<List<PageAllVersionDetailVO>> exportAllVersionDetail(
			@NotBlank(message = "应用ID不能为空")
			@Schema(description = "应用ID",example = "Fqs2CL9CUn7U1AqilSFXgb")
			@RequestParam String appId) {

		List<List<PageAllVersionDetailVO>> result = new ArrayList<>();
		for (int i = 0; i < 2; i++) {
			// 初始化结果集
			List<PageAllVersionDetailVO> allRecords = new ArrayList<>();
			// 分页查询参数
			PageAllVersionDetailDTO pageQuery = new PageAllVersionDetailDTO();
			pageQuery.setAppId(appId);
			pageQuery.setQueryDate(i);
			// 每次查询的批次大小，根据实际内存情况调整
			long batchSize = 1000;
			pageQuery.setSize(batchSize);
			pageQuery.setCurrent(1);

			while (true) {
				// 分批查询数据
				Page<PageAllVersionDetailVO> pageResult = userAnalyseService.pageAllVersionDetail(pageQuery);
				List<PageAllVersionDetailVO> records = pageResult.getRecords();
				if (CollectionUtils.isEmpty(records)) {
					// 没有更多数据，退出循环
					break;
				}
				// 添加到结果集
				allRecords.addAll(records);
				// 如果当前页记录数小于批次大小，说明是最后一页
				if (records.size() < batchSize) {
					break;
				}
				// 准备查询下一页
				pageQuery.setCurrent(pageQuery.getCurrent() + 1);
			}
			result.add(allRecords);
		}

		return result;
	}

	@PostMapping("/version/single/detail")
	@Operation(summary = "分页查询单版本详情")
	public R<Page<PageSingleVersionDetailVO>> pageSingleVersionDetail(@Valid @RequestBody PageUserAnalyseDTO reqDto) {
		Page<PageSingleVersionDetailVO> result = userAnalyseService.pageSingleVersionDetail(reqDto);
		return R.ok(result);
	}

	@PostMapping("/version/single/export")
	@Operation(summary = "导出单版本详情")
	public void exportSingleVersionDetail(
			@Valid @RequestBody UserAnalyseQueryBaseDTO reqDto,
			HttpServletResponse response) throws Exception {

		// 获取版本并验证
		if (reqDto.getVersion() == null || reqDto.getVersion().isEmpty()){
			throw new BusinessException("版本不能为空");
		}
		String version = reqDto.getVersion().get(0);
		String sheetName = version + "版本详情"; // 动态生成表名

		// 初始化结果集
		List<PageSingleVersionDetailVO> allRecords = new ArrayList<>();
		// 分页查询参数
		PageUserAnalyseDTO pageQuery = new PageUserAnalyseDTO();
		BeanUtils.copyProperties(reqDto, pageQuery);
		long batchSize = 1000;
		pageQuery.setSize(batchSize);
		pageQuery.setCurrent(1);

		// 分批查询数据
		while (true) {
			Page<PageSingleVersionDetailVO> pageResult = userAnalyseService.pageSingleVersionDetail(pageQuery);
			List<PageSingleVersionDetailVO> records = pageResult.getRecords();
			if (CollectionUtils.isEmpty(records)) {
				break;
			}
			allRecords.addAll(records);
			if (records.size() < batchSize) {
				break;
			}
			pageQuery.setCurrent(pageQuery.getCurrent() + 1);
		}

		// 设置响应头，动态生成文件名
		String fileName = URLEncoder.encode(sheetName, StandardCharsets.UTF_8)
				.replaceAll("\\+", "%20");
		response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
		response.setCharacterEncoding(StandardCharsets.UTF_8.name());
		response.setHeader("Content-disposition",
				"attachment;filename*=utf-8''" + fileName + ".xlsx");

		// 使用EasyExcel手动写入，指定动态表名
		EasyExcel.write(response.getOutputStream(), PageSingleVersionDetailVO.class)
				.sheet(sheetName) // 设置工作表名称
				.doWrite(allRecords);
	}

	@PostMapping("/version/distribution")
	@Operation(summary = "查询版本用户来源")
	public R<List<GetVersionDistributionVO>> getVersionDistribution(@Valid @RequestBody GetVersionDistributionDTO reqDto) {
		List<GetVersionDistributionVO> result = userAnalyseService.getVersionDistribution(reqDto);
		return R.ok(result);
	}

	@PostMapping("/version/distribution/detail")
	@Operation(summary = "分页查询版本用户来源详情")
	public R<Page<PageVersionDistributionDetailVO>> pageVersionDistributionDetail(@Valid @RequestBody PageVersionDistributionDetailDTO reqDto) {
		Page<PageVersionDistributionDetailVO> result = userAnalyseService.pageVersionDistributionDetail(reqDto);
		return R.ok(result);
	}

	@PostMapping("/version/distribution/export")
	@Operation(summary = "导出版本用户来源详情")
	public void exportVersionDistributionDetail(
			@Valid @RequestBody GetVersionDistributionDTO reqDto,
			HttpServletResponse response) throws Exception {

		// 1. 参数校验与获取
		String version = reqDto.getVersion();
		String type = reqDto.getType();
		if (version == null || version.isEmpty()) {
			throw new BusinessException("版本不能为空");
		}
		if (type == null || type.isEmpty()) {
			throw new BusinessException("类型不能为空");
		}

		// 2. 动态生成文件名和表头
		String fileName;
		List<List<String>> head = new ArrayList<>();
		String sheetName = version + "版本用户来源详情"; // 固定sheet名

		switch (type) {
			case "newUserChannel":
				fileName = version + "版本新增用户渠道详情";
				head.add(Collections.singletonList("渠道"));
				head.add(Collections.singletonList("新增用户"));
				head.add(Collections.singletonList("新增用户占比"));
				break;
			case "upgradeChannel":
				fileName = version + "版本升级用户渠道详情";
				head.add(Collections.singletonList("渠道"));
				head.add(Collections.singletonList("升级用户"));
				head.add(Collections.singletonList("升级用户占比"));
				break;
			case "upgradeVersion":
				fileName = version + "版本升级用户版本详情";
				head.add(Collections.singletonList("版本"));
				head.add(Collections.singletonList("升级用户"));
				head.add(Collections.singletonList("升级用户占比"));
				break;
			default:
				throw new BusinessException("不支持的导出类型: " + type);
		}

		// 3. 设置Excel响应头（确保文件类型正确）
		response.reset();
		response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
		response.setCharacterEncoding(StandardCharsets.UTF_8.name());
		String encodedFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8).replaceAll("\\+", "%20");
		response.setHeader("Content-Disposition",
				"attachment;filename=\"" + encodedFileName + ".xlsx\";" +
						"filename*=utf-8''" + encodedFileName + ".xlsx");

		// 4. 分页查询数据
		List<PageVersionDistributionDetailVO> allRecords = new ArrayList<>();
		PageVersionDistributionDetailDTO pageQuery = new PageVersionDistributionDetailDTO();
		BeanUtils.copyProperties(reqDto, pageQuery);
		long batchSize = 1000;
		pageQuery.setSize(batchSize);
		pageQuery.setCurrent(1);

		while (true) {
			Page<PageVersionDistributionDetailVO> pageResult = userAnalyseService.pageVersionDistributionDetail(pageQuery);
			List<PageVersionDistributionDetailVO> records = pageResult.getRecords();
			if (records == null || records.isEmpty()) {
				break;
			}
			allRecords.addAll(records);
			if (records.size() < batchSize) {
				break;
			}
			pageQuery.setCurrent(pageQuery.getCurrent() + 1);
		}

		// 使用EasyExcel手动写入，指定动态表名
		EasyExcel.write(response.getOutputStream())
				.head(head)
				.sheet(sheetName)
				.doWrite(allRecords);
	}

/***************************************** 公用接口 *****************************************/
	@GetMapping("/version/list")
	@Operation(summary = "获取应用版本列表")
	public R<List<String>> getVersionList(
			@NotBlank(message = "应用ID不能为空")
			@Schema(description = "应用ID",example = "Fqs2CL9CUn7U1AqilSFXgb")
			@RequestParam String appId) {
		if (appId == null || appId.isEmpty()){
			throw new BusinessException("appId不能为空");
		}
		List<String> result = userAnalyseService.getVersionList(appId);
		return R.ok(result);
	}

	@GetMapping("/channel/list")
	@Operation(summary = "获取应用渠道列表", description = "根据应用ID查询该应用下的所有渠道列表")
	public R<List<String>> getChannelList(
			@NotBlank(message = "应用ID不能为空")
			@Schema(description = "应用ID", example = "Fqs2CL9CUn7U1AqilSFXgb")
			@RequestParam String appId) {
		List<String> result = userAnalyseService.getChannelList(appId);
		return R.ok(result);
	}
}
