

package org.jeecg.modules.stm.audit.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.config.Configure;
import com.deepoove.poi.config.ConfigureBuilder;
import com.deepoove.poi.policy.DocumentRenderPolicy;


import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.system.base.controller.JeecgController;
import org.jeecg.modules.stm.audit.entity.*;
import org.jeecg.modules.stm.audit.service.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import jakarta.servlet.http.HttpServletRequest;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import static org.jeecg.modules.stm.utils.StmConstans.REPORT_SAVE_PATH;
import static org.jeecg.modules.stm.utils.StmConstans.REPORT_TEMPLATE_PATH;

  
@RestController
@RequestMapping("/audit/auditProjectReport")
@Slf4j
public class AuditProjectReportController extends JeecgController<AuditProjectItem, IAuditProjectItemService> {

	@Autowired
	private IAuditProjectService auditProjectService;
	@Autowired
	private IAuditProjectReportConfigService auditProjectReportConfigService;
	@Autowired
	private IAuditProjectReportTitleService auditProjectReportTitleService;
	@Autowired
	private IAuditProjectProblemService auditProjectProblemService;
	@Autowired
	private IAuditProjectProblemRelItemService auditProjectProblemRelItemService;
	@Autowired
	private IAuditTaskReportService auditTaskReportService;
	@Autowired
	private IAuditProjectItemService auditProjectItemService;

	private Map<String, Object> dataTemplate;
	private ConfigureBuilder builder;
	private String bizname = "report";

	@Value(value = "${jeecg.path.upload}")
	private String uploadpath;

	@GetMapping(value = "/createDocReport")
	public Result<AuditProjectReportConfig> createDocReport(HttpServletRequest request, Integer projectId) {
		try {
			log.info("开始生成项目{}的报告", projectId);

			AuditProjectReportConfig reportConfig = getProjectReportConfig(projectId);
			if (reportConfig == null) {
				return Result.error("未找到报告配置");
			}

			String reportFileName = getFileName(reportConfig);
			String templatePath = uploadpath + REPORT_TEMPLATE_PATH;
			String filePathUri = REPORT_SAVE_PATH + reportFileName;
			String saveFilePath = validateAndGetSavePath(reportFileName);

			log.debug("使用模板路径: {}, 保存路径: {}", templatePath, saveFilePath);

			this.dataTemplate = new HashMap<>();
			this.builder = Configure.builder();

			prepareReportData(reportConfig, projectId);

			Configure config = builder.build();

			try (XWPFTemplate template = XWPFTemplate.compile(templatePath, config).render(dataTemplate);
				 FileOutputStream out = new FileOutputStream(saveFilePath)) {
				template.write(out);
				out.flush();
			}

			reportConfig.setReportUrl(filePathUri);
			auditProjectReportConfigService.updateById(reportConfig);

			log.info("成功生成报告文件: {}", saveFilePath);
			return Result.OK("创建成功", reportConfig);

		} catch (SecurityException e) {
			log.error("非法文件路径", e);
			return Result.error("非法文件路径");
		} catch (IOException e) {
			log.error("文件操作失败", e);
			return Result.error("生成报告文件失败");
		} catch (Exception e) {
			log.error("生成报告异常", e);
			return Result.error("生成报告失败");
		}
	}

	/**
	 * 准备报告数据（主方法）
	 */
	private void prepareReportData(AuditProjectReportConfig reportConfig, Integer projectId) {
		// 1. 设置基础配置数据
		setBasicReportConfig(reportConfig);

		// 2. 设置当前日期
		setDataTemplateCurDate();

		// 3. 设置项目相关数据
		setProjectRelatedData(projectId);
	}

	/**
	 * 设置基础报告配置数据
	 */
	private void setBasicReportConfig(AuditProjectReportConfig reportConfig) {
		this.dataTemplate.put("reportName", reportConfig.getReportName());
		this.dataTemplate.put("companyName", reportConfig.getCompanyName());
		this.dataTemplate.put("reportDate", reportConfig.getReportDate());
		this.dataTemplate.put("startDate", reportConfig.getStartDate());
		this.dataTemplate.put("endDate", reportConfig.getEndDate());
	}

	/**
	 * 设置当前日期
	 */
	private void setDataTemplateCurDate() {
		LocalDate currentDate = LocalDate.now();
		DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日");
		String formattedDate = currentDate.format(formatter);
		this.dataTemplate.put("curDate", formattedDate);
	}

	/**
	 * 设置项目相关数据
	 */
	private void setProjectRelatedData(Integer projectId) {
		// 获取所有标题并构建完整树形结构
		List<AuditProjectReportTitle> allTitles = getProjectReportTitle(projectId);
		List<AuditProjectReportTitle> titleTree = buildTitleTree(allTitles);

		// 获取问题数据
		List<AuditProjectProblem> problems = getProjectProblem(projectId);
		List<AuditProjectProblemRelItem> relItems = getProjectProblemRelItem(projectId);

		// 获取任务报告数据
		List<AuditTaskReport> taskReports = getProjectTaskReport(projectId);
		Map<Integer, AuditTaskReport> taskReportMap = taskReports.stream()
				.collect(Collectors.toMap(AuditTaskReport::getId, Function.identity()));

		// 处理问题与条目的关联关系
		processProblemItemRelations(problems, relItems);

		// 分类问题数据
		Map<Integer, List<AuditProjectProblem>> issuesMap = new HashMap<>();
		Map<Integer, List<AuditProjectProblem>> situationMap = new HashMap<>();
		classifyProblems(problems, issuesMap, situationMap);

		// 处理标题和问题数据
		processTitleAndProblems(titleTree, issuesMap, situationMap, taskReportMap);
	}

	/**
	 * 构建完整的标题树形结构
	 */
	private List<AuditProjectReportTitle> buildTitleTree(List<AuditProjectReportTitle> titles) {
		List<AuditProjectReportTitle> tree = new ArrayList<>();
		Map<Integer, AuditProjectReportTitle> nodeMap = new HashMap<>();

		// 第一遍：将所有节点放入map
		for (AuditProjectReportTitle node : titles) {
			nodeMap.put(node.getId(), node);
		}

		// 第二遍：构建树形结构
		for (AuditProjectReportTitle node : titles) {
			Integer parentId = node.getParentId();
			if (parentId == null || parentId == 0) {
				tree.add(node);
			} else {
				AuditProjectReportTitle parent = nodeMap.get(parentId);
				if (parent != null) {
					if (parent.getChildren() == null) {
						parent.setChildren(new ArrayList<>());
					}
					parent.getChildren().add(node);
					parent.setHasChild(1);
				}
			}
		}

		return tree;
	}

	/**
	 * 处理问题与条目的关联关系
	 */
	private void processProblemItemRelations(List<AuditProjectProblem> problems,
											 List<AuditProjectProblemRelItem> relItems) {
		Map<Integer, List<Integer>> relItemMap = new HashMap<>();
		for (AuditProjectProblemRelItem relItem : relItems) {
			relItemMap.computeIfAbsent(relItem.getProblemid(), k -> new ArrayList<>())
					.add(relItem.getItemid());
		}
		for (AuditProjectProblem item : problems) {
			item.setItemIdList(relItemMap.get(item.getId()));
		}
	}

	/**
	 * 分类问题数据
	 */
	private void classifyProblems(List<AuditProjectProblem> problems,
								  Map<Integer, List<AuditProjectProblem>> issuesMap,
								  Map<Integer, List<AuditProjectProblem>> situationMap) {
		for (AuditProjectProblem item : problems) {
			if(item.getTp() == 1) {
				situationMap.computeIfAbsent(item.getTitleId(),
						k -> new ArrayList<>()).add(item);

			} else {
				issuesMap.computeIfAbsent(item.getTitleId(),
						k -> new ArrayList<>()).add(item);
			}
		}
	}

	/**
	 * 处理标题和问题数据
	 */
	private void processTitleAndProblems(List<AuditProjectReportTitle> titleTree,
										 Map<Integer, List<AuditProjectProblem>> issuesMap,
										 Map<Integer, List<AuditProjectProblem>> situationMap,
										 Map<Integer, AuditTaskReport> taskReportMap) {
		// 查找包含issues的标题树
		List<AuditProjectReportTitle> titleIssues = findTitlesWithData(titleTree, issuesMap, taskReportMap, true);

		// 查找包含situations的标题树
		List<AuditProjectReportTitle> titleSituations = findTitlesWithData(titleTree, situationMap, taskReportMap, false);

		mergeSituationsToTitle(titleSituations);

		this.dataTemplate.put("iss", titleIssues);
		this.dataTemplate.put("sit", titleSituations);
	}

	/**
	 * 查找包含数据的标题树（递归方法）
	 */
	private List<AuditProjectReportTitle> findTitlesWithData(List<AuditProjectReportTitle> titles,
															 Map<Integer, List<AuditProjectProblem>> dataMap,
															 Map<Integer, AuditTaskReport> taskReportMap,
															 boolean isIssues) {
		List<AuditProjectReportTitle> result = new ArrayList<>();

		for (AuditProjectReportTitle title : titles) {
			// 复制当前节点（避免修改原始数据）
			AuditProjectReportTitle copyTitle = copyTitle(title);

			// 处理当前节点的数据
			if (dataMap.containsKey(title.getId())) {
				List<AuditProjectProblem> problems = dataMap.get(title.getId());
				copyTitle.setProblems(problems);

				// 根据类型处理问题数据
				if (isIssues) {
					processIssuesData(problems, taskReportMap);
				} else {
					processSituationData(problems, taskReportMap);
				}
			}

			// 递归处理子节点
			if (title.getChildren() != null && !title.getChildren().isEmpty()) {
				List<AuditProjectReportTitle> childResults = findTitlesWithData(
						title.getChildren(), dataMap, taskReportMap, isIssues);

				if (!childResults.isEmpty()) {
					copyTitle.setChildren(childResults);
					result.add(copyTitle);
				} else if (copyTitle.getProblems() != null && !copyTitle.getProblems().isEmpty()) {
					result.add(copyTitle);
				}
			} else if (copyTitle.getProblems() != null && !copyTitle.getProblems().isEmpty()) {
				result.add(copyTitle);
			}
		}

		return result;
	}

	/**
	 * 复制标题节点
	 */
	private AuditProjectReportTitle copyTitle(AuditProjectReportTitle original) {
		AuditProjectReportTitle copy = new AuditProjectReportTitle();
		copy.setId(original.getId());
		copy.setParentId(original.getParentId());
		copy.setTitle(original.getTitle());
		copy.setHasChild(original.getHasChild());
		// 注意：不复制children和problems，后面会单独处理
		return copy;
	}

	/**
	 * 处理issues数据
	 */
	private void processIssuesData(List<AuditProjectProblem> problems,
								   Map<Integer, AuditTaskReport> taskReportMap) {
		for (AuditProjectProblem problem : problems) {
			List<Map<String, Object>> issuesList = new ArrayList<>();
			int issuesInd = 1;

			for (Integer itemId : problem.getItemIdList()) {
				AuditTaskReport taskReport = taskReportMap.get(itemId);
				if (taskReport != null) {
					String issues = taskReport.getIssues();
					if (issues != null && !issues.isEmpty()) {
						Map<String, Object> issuesTempMap = new HashMap<>();
						issuesTempMap.put("content", issues);
						issuesTempMap.put("ind", issuesInd++);
						issuesList.add(issuesTempMap);
					}
				}
			}
			problem.setIssues(issuesList);
		}
	}

	/**
	 * 处理situation数据
	 */
	private void processSituationData(List<AuditProjectProblem> problems,
									  Map<Integer, AuditTaskReport> taskReportMap) {
		for (AuditProjectProblem problem : problems) {
			List<Map<String, Object>> situationList = new ArrayList<>();
			int ind = 1;
			for (Integer itemId : problem.getItemIdList()) {
				AuditTaskReport taskReport = taskReportMap.get(itemId);
				if (taskReport != null) {
					String situation = taskReport.getSituation();
					if (situation != null && !situation.isEmpty()) {
						Map<String, Object> situationMap = new HashMap<>();
						situationMap.put("content", situation);
						situationMap.put("ind", ind++);
						situationList.add(situationMap);
					}
				}
			}
			problem.setSituations(situationList);
		}
	}

	/**
	 * 查询报告配置
	 */
	private AuditProjectReportConfig getProjectReportConfig(Integer projectId) {
		QueryWrapper<AuditProjectReportConfig> queryWrapper = new QueryWrapper<>();
		queryWrapper.eq("project_id", projectId);
		List<AuditProjectReportConfig> list = auditProjectReportConfigService.list(queryWrapper);
		return list.isEmpty() ? null : list.get(0);
	}

	/**
	 * 查询报告标题
	 */
	private List<AuditProjectReportTitle> getProjectReportTitle(Integer projectId) {
		QueryWrapper<AuditProjectReportTitle> queryWrapper = new QueryWrapper<>();
		queryWrapper.eq("project_id", projectId);
		return auditProjectReportTitleService.list(queryWrapper);
	}

	/**
	 * 查询报告评价分组
	 */
	private List<AuditProjectProblem> getProjectProblem(Integer projectId) {
		QueryWrapper<AuditProjectProblem> queryWrapper = new QueryWrapper<>();
		queryWrapper.eq("project_id", projectId);
		return auditProjectProblemService.list(queryWrapper);
	}

	private List<AuditProjectProblemRelItem> getProjectProblemRelItem(Integer projectId) {
		QueryWrapper<AuditProjectProblemRelItem> queryWrapper = new QueryWrapper<>();
		queryWrapper.eq("projectid", projectId);
		return auditProjectProblemRelItemService.list(queryWrapper);
	}

	/**
	 * 查询项目的条目
	 */
	private List<AuditProjectItem> getProjectItem(Integer projectId) {
		QueryWrapper<AuditProjectItem> queryWrapper = new QueryWrapper<>();
		queryWrapper.eq("pid", projectId);
		return auditProjectItemService.list(queryWrapper);
	}

	/**
	 * 查询项目评价
	 */
	private List<AuditTaskReport> getProjectTaskReport(Integer projectId) {
		QueryWrapper<AuditTaskReport> queryWrapper = new QueryWrapper<>();
		queryWrapper.eq("projectid", projectId);
		return auditTaskReportService.list(queryWrapper);
	}

	/**
	 * 生成文件名称
	 */
	private String getFileName(AuditProjectReportConfig reportConfig) {
		String reportName = reportConfig.getReportName();
		String reportDate = reportConfig.getReportDate();
		return reportName + "-" + reportDate + ".docx";
	}

	/**
	 * 验证并获取保存路径
	 */
	private String validateAndGetSavePath(String fileName) throws IOException {
		Path path = Paths.get(uploadpath, REPORT_SAVE_PATH, fileName).normalize();
		if (!path.startsWith(Paths.get(uploadpath).normalize())) {
			throw new SecurityException("非法文件路径");
		}

		// 确保目录存在
		Files.createDirectories(path.getParent());
		return path.toString();
	}

	/**
	 * 设置模板配置
	 */
	private void setConfig(String strKey) {
		this.builder.bind(strKey, new DocumentRenderPolicy());
	}

	/**
	 * 合并所有problem的situations到title对象
	 */
	private void mergeSituationsToTitle(List<AuditProjectReportTitle> titleSituations) {
		for (AuditProjectReportTitle title : titleSituations) {
			List<Map<String, Object>> mergedSituations = new ArrayList<>();
			int situationIndex = 1;

			// 合并当前title下所有problem的situations
			if (title.getProblems() != null) {
				for (AuditProjectProblem problem : title.getProblems()) {
					if (problem.getSituations() != null) {
						for (Map<String, Object> situation : problem.getSituations()) {
							Map<String, Object> mergedSituation = new HashMap<>();
							mergedSituation.put("content", situation.get("content"));
							mergedSituation.put("ind", situationIndex++);
							mergedSituations.add(mergedSituation);
						}
					}
				}
			}

			// 将合并后的situations设置到title对象
			title.setSituations(mergedSituations);

			// 递归处理子节点
			if (title.getChildren() != null) {
				mergeSituationsToTitle(title.getChildren());
			}
		}
	}
}