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

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;


import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.aspect.annotation.AutoLog;
import org.jeecg.common.system.api.ISysBaseAPI;
import org.jeecg.common.system.base.controller.JeecgController;
import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.modules.system.entity.SysUser;
import org.jeecg.modules.system.service.ISysUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import org.jeecg.modules.stm.metric.entity.MetricMonitorSet;
import org.jeecg.modules.stm.metric.entity.MetricReport;
import org.jeecg.modules.stm.metric.service.IMetricMonitorSetService;
import org.jeecg.modules.stm.metric.service.IMetricReportService;
import org.jeecg.modules.stm.utils.CommonUtil;
import org.jeecg.modules.stm.utils.MessageParam;
import org.jeecg.modules.stm.utils.SendMessageUtil;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

/**
 * @Description: 监测记录
 * @Author: jeecg-boot
 * @Date:   2023-07-15
 * @Version: V1.0
 */
  
@RestController
@RequestMapping("/metric/metricReport")
@Slf4j
public class MetricReportController extends JeecgController<MetricReport, IMetricReportService> {
	@Autowired
	private IMetricReportService metricReportService;
	@Autowired
	private IMetricMonitorSetService metricMonitorSetService;
	@Autowired
	private ISysUserService sysUserService;
	@Autowired
	private ISysBaseAPI sysBaseAPI;

	// 使用固定大小的线程池处理异步任务
	private final Executor asyncExecutor = Executors.newFixedThreadPool(10);

	/**
	 * 分页列表查询
	 */
	  
	@GetMapping(value = "/list")
	public Result<IPage<MetricReport>> queryPageList(MetricReport metricReport,
													 @RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
													 @RequestParam(name="pageSize", defaultValue="10") Integer pageSize,
													 HttpServletRequest req) {
		try {
			QueryWrapper<MetricReport> queryWrapper = QueryGenerator.initQueryWrapper(metricReport, req.getParameterMap());
			Page<MetricReport> page = new Page<>(pageNo, pageSize);
			IPage<MetricReport> pageList = metricReportService.page(page, queryWrapper);
			return Result.OK(pageList);
		} catch (Exception e) {
			log.error("分页查询监测记录失败", e);
			return Result.error("分页查询监测记录失败");
		}
	}

	@GetMapping(value = "/queryAllList")
	public Result<Map<String,Object>> queryAllList(@RequestParam(name="mtrcNos") String mtrcNos,
												   @RequestParam(name="stFillTime") String stFillTime,
												   @RequestParam(name="endFillTime") String endFillTime,
												   HttpServletRequest req) {
		try {
			String[] mtrcNoAry = mtrcNos.split(",");
			Map<String,Object> retMap = new HashMap<>();

			if(mtrcNoAry.length>1) {
				QueryWrapper<MetricMonitorSet> queryMonitorWrapper = new QueryWrapper<>();
				queryMonitorWrapper.in("mtrc_no", mtrcNoAry);
				queryMonitorWrapper.orderByAsc("coll_freq");
				List<MetricMonitorSet> mtrcList = metricMonitorSetService.list(queryMonitorWrapper);
				retMap.put("mtrcList", mtrcList);
			}

			QueryWrapper<MetricReport> queryWrapper = new QueryWrapper<>();
			queryWrapper.in("mtrc_no", mtrcNoAry);
			if(stFillTime!=null && !stFillTime.isEmpty()) {
				queryWrapper.ge("fill_time", stFillTime);
			}
			if(endFillTime!=null && !endFillTime.isEmpty()) {
				queryWrapper.le("fill_time", endFillTime);
			}
			queryWrapper.orderByAsc("fill_time");
			List<MetricReport> list = metricReportService.list(queryWrapper);

			retMap.put("dataList", list);
			return Result.OK(retMap);
		} catch (Exception e) {
			log.error("查询全部监测记录失败", e);
			return Result.error("查询全部监测记录失败");
		}
	}

	  
	@GetMapping(value = "/queryList")
	public Result<List<MetricReport>> queryList(MetricReport metricReport, HttpServletRequest req) {
		try {
			QueryWrapper<MetricReport> queryWrapper = new QueryWrapper<>();
			queryWrapper.eq("mtrc_no", metricReport.getMtrcNo())
					.orderByDesc("id");
			List<MetricReport> list = metricReportService.list(queryWrapper);
			return Result.OK(list);
		} catch (Exception e) {
			log.error("查询监测记录列表失败", e);
			return Result.error("查询监测记录列表失败");
		}
	}

	/**
	 * 添加监测记录
	 */
	@AutoLog(value = "监测记录-添加")
	  
	@RequiresPermissions("metric:metric_report:add")
	@PostMapping(value = "/add")
	public Result<String> add(@RequestBody MetricReport metricReport) {
		try {
			LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
			metricReport.setReporter(sysUser.getId());

			QueryWrapper<MetricMonitorSet> queryWrapper = new QueryWrapper<>();
			queryWrapper.eq("mtrc_no", metricReport.getMtrcNo());
			MetricMonitorSet mmSet = metricMonitorSetService.getOne(queryWrapper);

			if (mmSet == null) {
				return Result.error("未找到对应的监测指标配置");
			}

			Double vals = Double.valueOf(metricReport.getFillVals());
			Integer riskLevel = CommonUtil.computeRiskLevel(vals, mmSet);
			metricReport.setRiskLevel(riskLevel);

			boolean saveResult = metricReportService.save(metricReport);
			if (!saveResult) {
				return Result.error("保存监测记录失败");
			}

			if (metricReport.getFillVals() != null && metricReport.getRiskLevel() != null) {
				// 异步发送邮件和通知
				CompletableFuture.runAsync(() -> {
					try {
						sendMail(metricReport);
					} catch (Exception e) {
						log.error("异步发送邮件失败", e);
					}
				}, asyncExecutor);
			}

			return Result.OK("保存成功！");
		} catch (NumberFormatException e) {
			log.error("填报值格式错误", e);
			return Result.error("填报值格式错误");
		} catch (Exception e) {
			log.error("添加监测记录失败", e);
			return Result.error("添加监测记录失败: " + e.getMessage());
		}
	}

	/**
	 * 编辑监测记录
	 */
	@AutoLog(value = "监测记录-编辑")
	  
	@RequiresPermissions("metric:metric_report:edit")
	@RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
	public Result<String> edit(@RequestBody MetricReport metricReport) {
		try {
			if (metricReport.getFillVals() == null && metricReport.getDes() == null && metricReport.getFillTime() == null) {
				return Result.error("值不能为空!");
			}
			if (metricReport.getFillVals() != null) {
				QueryWrapper<MetricMonitorSet> queryWrapper = new QueryWrapper<>();
				queryWrapper.eq("mtrc_no", metricReport.getMtrcNo());
				MetricMonitorSet mmSet = metricMonitorSetService.getOne(queryWrapper);

				if (mmSet == null) {
					return Result.error("未找到对应的监测指标配置");
				}

				Double vals = Double.valueOf(metricReport.getFillVals());
				Integer riskLevel = CommonUtil.computeRiskLevel(vals, mmSet);
				metricReport.setRiskLevel(riskLevel);


			}
			boolean updateResult = metricReportService.updateById(metricReport);
			if (!updateResult) {
				return Result.error("更新监测记录失败");
			}
			if (metricReport.getFillVals() != null && metricReport.getRiskLevel() != null) {
				// 异步发送邮件和通知
				CompletableFuture.runAsync(() -> {
					try {
						sendMail(metricReport);
					} catch (Exception e) {
						log.error("异步发送邮件失败", e);
					}
				}, asyncExecutor);
			}
			return Result.OK("保存成功!");
		} catch (NumberFormatException e) {
			log.error("填报值格式错误", e);
			return Result.error("填报值格式错误");
		} catch (Exception e) {
			log.error("编辑监测记录失败", e);
			return Result.error("编辑监测记录失败: " + e.getMessage());
		}
	}

	/**
	 * 通过id删除
	 */
	@AutoLog(value = "监测记录-通过id删除")
	  
	@RequiresPermissions("metric:metric_report:delete")
	@DeleteMapping(value = "/delete")
	public Result<String> delete(@RequestParam(name="id",required=true) String id) {
		try {
			boolean removeResult = metricReportService.removeById(id);
			return removeResult ? Result.OK("删除成功!") : Result.error("删除失败");
		} catch (Exception e) {
			log.error("删除监测记录失败", e);
			return Result.error("删除监测记录失败");
		}
	}

	/**
	 * 批量删除
	 */
	@AutoLog(value = "监测记录-批量删除")
	  
	@RequiresPermissions("metric:metric_report:deleteBatch")
	@DeleteMapping(value = "/deleteBatch")
	public Result<String> deleteBatch(@RequestParam(name="ids",required=true) String ids) {
		try {
			List<String> idList = Arrays.asList(ids.split(","));
			boolean removeResult = metricReportService.removeByIds(idList);
			return removeResult ? Result.OK("批量删除成功!") : Result.error("批量删除失败");
		} catch (Exception e) {
			log.error("批量删除监测记录失败", e);
			return Result.error("批量删除监测记录失败");
		}
	}

	/**
	 * 通过id查询
	 */
	  
	@GetMapping(value = "/queryById")
	public Result<MetricReport> queryById(@RequestParam(name="id",required=true) String id) {
		try {
			MetricReport metricReport = metricReportService.getById(id);
			if(metricReport == null) {
				return Result.error("未找到对应数据");
			}
			return Result.OK(metricReport);
		} catch (Exception e) {
			log.error("查询监测记录失败", e);
			return Result.error("查询监测记录失败");
		}
	}

	/**
	 * 导出excel
	 */
	@RequiresPermissions("metric:metric_report:exportXls")
	@RequestMapping(value = "/exportXls")
	public ModelAndView exportXls(HttpServletRequest request, MetricReport metricReport) {
		return super.exportXls(request, metricReport, MetricReport.class, "监测记录");
	}

	/**
	 * 通过excel导入数据
	 */
	@RequiresPermissions("metric:metric_report:importExcel")
	@RequestMapping(value = "/importExcel", method = RequestMethod.POST)
	public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) {
		return super.importExcel(request, response, MetricReport.class);
	}

	@GetMapping(value = "/addBatch")
	public Result<String> addBatch(@RequestParam String mtrcNo, @RequestParam Integer freq) {
		try {
			LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
			String uid = sysUser.getId();
			List<MetricReport> listMetricReport = new ArrayList<>();

			QueryWrapper<MetricReport> queryWrapper = new QueryWrapper<>();
			queryWrapper.eq("mtrc_no", mtrcNo).orderByDesc("fill_time").last("limit 1");
			List<MetricReport> lastMetricList = metricReportService.list(queryWrapper);
			Date lastFillTime = lastMetricList != null && !lastMetricList.isEmpty() ? lastMetricList.get(0).getFillTime() : null;

			if (isExist(lastFillTime)) {
				return Result.OK("记录已经存在！");
			}

			List<Date> listTimes = getDateListByFrequency(freq, lastFillTime);
			if (listTimes == null || listTimes.isEmpty()) {
				return Result.error("无法生成有效的时间列表");
			}

			for (Date date : listTimes) {
				MetricReport mr = new MetricReport();
				mr.setReporter(uid);
				mr.setMtrcNo(mtrcNo);
				mr.setFillTime(date);
				listMetricReport.add(mr);
			}

			boolean saveResult = metricReportService.saveBatch(listMetricReport);
			return saveResult ? Result.OK("添加成功！") : Result.error("添加失败");
		} catch (Exception e) {
			log.error("批量添加监测记录失败", e);
			return Result.error("批量添加监测记录失败");
		}
	}

	private List<Date> getDateListByFrequency(Integer freq, Date lastFillTime) {
		switch (freq) {
			case 1: return getCurMonthDates(lastFillTime);
			case 2: return getCurYearWeek(lastFillTime);
			case 3: return getCurYearMonths(lastFillTime);
			case 4: return getCurYearOther(lastFillTime, 3);
			case 5: return getCurYearOther(lastFillTime, 6);
			case 6: return getCurYearOther(lastFillTime, 12);
			case 11: return getCurDayHour();
			default:
				List<Date> defaultList = new ArrayList<>();
				defaultList.add(new Date());
				return defaultList;
		}
	}

	private List<Date> getCurMonthDates(Date fDate) {
		LocalDate endDate = LocalDate.now();
		LocalDate stDate = null;
		List<Date> allDates = new ArrayList<>();

		if(fDate == null) {
			allDates.add(new Date());
		} else {
			stDate = fDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
			stDate = stDate.plusDays(1);
			while (!stDate.isAfter(endDate)) {
				allDates.add(Date.from(stDate.atStartOfDay(ZoneId.systemDefault()).toInstant()));
				stDate = stDate.plusDays(1);
			}
		}
		return allDates;
	}

	private List<Date> getCurYearMonths(Date fDate) {
		LocalDate endDate = LocalDate.now();
		LocalDate stDate = null;
		List<Date> allDates = new ArrayList<>();

		if(fDate != null) {
			stDate = fDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
			stDate = stDate.plusMonths(1);
			endDate = endDate.plusMonths(1);
			if(stDate.isAfter(endDate)) {
				return null;
			}
			while (!stDate.isAfter(endDate)) {
				allDates.add(Date.from(stDate.atStartOfDay(ZoneId.systemDefault()).toInstant()));
				stDate = stDate.plusMonths(1);
			}
		} else {
			allDates.add(Date.from(endDate.atStartOfDay(ZoneId.systemDefault()).toInstant()));
		}
		return allDates;
	}

	private List<Date> getCurYearWeek(Date fDate) {
		LocalDate endDate = LocalDate.now();
		LocalDate stDate = null;
		List<Date> allDates = new ArrayList<>();

		if(fDate != null) {
			stDate = fDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
			stDate = stDate.plusWeeks(1);
			LocalDate endDayOfWeek = endDate.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
			if(stDate.isAfter(endDate)) {
				return null;
			}
			while (!stDate.isAfter(endDayOfWeek)) {
				allDates.add(Date.from(stDate.atStartOfDay(ZoneId.systemDefault()).toInstant()));
				stDate = stDate.plusWeeks(1);
			}
		} else {
			allDates.add(Date.from(endDate.atStartOfDay(ZoneId.systemDefault()).toInstant()));
		}
		return allDates;
	}

	private List<Date> getCurDayHour() {
		List<Date> allDates = new ArrayList<>();
		for(int i=0; i<24; i++) {
			Calendar calendar = Calendar.getInstance();
			calendar.set(Calendar.HOUR_OF_DAY, i);
			calendar.set(Calendar.MINUTE, 0);
			calendar.set(Calendar.SECOND, 0);
			calendar.set(Calendar.MILLISECOND, 0);
			allDates.add(calendar.getTime());
		}
		return allDates;
	}

	private List<Date> getCurYearOther(Date fDate, int k) {
		List<Date> allDates = new ArrayList<>();
		LocalDate endDate = LocalDate.now();
		LocalDate stDate = null;

		if(fDate != null) {
			stDate = fDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
			stDate = stDate.plusMonths(k);
			if(stDate.isAfter(endDate)) return null;
			while (!stDate.isAfter(endDate)) {
				allDates.add(Date.from(stDate.atStartOfDay(ZoneId.systemDefault()).toInstant()));
				stDate = stDate.plusMonths(k);
			}
		} else {
			allDates.add(Date.from(endDate.atStartOfDay(ZoneId.systemDefault()).toInstant()));
		}
		return allDates;
	}

	private boolean isExist(Date fDate) {
		if(fDate == null) return false;
		LocalDate date1 = LocalDate.now();
		LocalDate date2 = fDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
		return date1.isEqual(date2);
	}

	/**
	 * 异步发送邮件和通知
	 */
	private void sendMail(MetricReport metricReport) {
		try {
			QueryWrapper<MetricMonitorSet> queryWrapper = new QueryWrapper<>();
			String mtrcNo = metricReport.getMtrcNo();
			Integer riskLevel = metricReport.getRiskLevel();
			queryWrapper.eq("mtrc_no", mtrcNo);
			MetricMonitorSet mSet = metricMonitorSetService.getOne(queryWrapper);

			if (mSet == null) {
				log.warn("未找到对应的监测指标配置: {}", mtrcNo);
				return;
			}

			String userName = getRiskLevelReceiver(mSet, riskLevel);
			if (userName == null || userName.isEmpty()) {
				log.info("未配置风险等级{}的通知接收人，指标编号: {}", riskLevel, mtrcNo);
				return;
			}

			QueryWrapper<SysUser> queryUserWrapper = new QueryWrapper<>();
			String[] userNameAry =  userName.split(",");
			queryUserWrapper.in("username", userNameAry);
			List<SysUser> sysUserList = sysUserService.list(queryUserWrapper);

			if (sysUserList == null||sysUserList.isEmpty()) {
				log.warn("未找到对应的用户: {}", userName);
				return;
			}

			// 构建邮件内容和标题
			String[] mailContent = buildMailContent(metricReport, mSet, riskLevel);
			String title = mailContent[0];
			String content = mailContent[1];

			// 发送邮件
			for(SysUser sysUser: sysUserList) {
				sendNotice(sysUser, title, content);
				String es_receiver = sysUser.getEmail();
				if (es_receiver != null && !es_receiver.isEmpty()) {
					sysBaseAPI.sendEmailMsg(es_receiver, title, content);
					//log.info("邮件发送成功，收件人: {}, 标题: {}", es_receiver, title);
				}
			}

			// 发送系统通知

		} catch (Exception e) {
			log.error("发送邮件和通知失败", e);
			throw new RuntimeException("发送邮件和通知失败", e);
		}
	}

	private String getRiskLevelReceiver(MetricMonitorSet mSet, Integer riskLevel) {
		switch (riskLevel) {
			case 1: return mSet.getNoticeReceiveLow();
			case 2: return mSet.getNoticeReceiveMiddle();
			case 3: return mSet.getNoticeReceiveHight();
			default: return null;
		}
	}

	private String[] buildMailContent(MetricReport metricReport, MetricMonitorSet mSet, Integer riskLevel) {
		String metricName = mSet.getMtrcName();
		StringBuffer titleSb = new StringBuffer();
		StringBuffer contentSb = new StringBuffer();

		contentSb.append("指标名称：").append(metricName)
				.append(",\n指标编号：").append(mSet.getMtrcNo());

		titleSb.append("风险指标[").append(metricName).append("]");

		switch (riskLevel) {
			case 1:
				titleSb.append("，低风险");
				contentSb.append(",\n风险等级：").append("低风险");
				break;
			case 2:
				titleSb.append("，中风险");
				contentSb.append(",\n风险等级：").append("中风险");
				break;
			case 3:
				titleSb.append("，高风险");
				contentSb.append(",\n风险等级：").append("高风险");
				break;
		}

		contentSb.append(",\n填报值：").append(metricReport.getFillVals());

		return new String[]{titleSb.toString(), contentSb.toString()};
	}

	private void sendNotice(SysUser sysUser, String strTitle, String strContent) {
		try {
			MessageParam messageParam = new MessageParam();
			SendMessageUtil sendMessageUtil = new SendMessageUtil(sysBaseAPI);
			messageParam.setMsgTitle(strTitle);
			messageParam.setContent(strContent);
			messageParam.setReceiver(sysUser.getUsername());
			messageParam.setTemplateCode("sys_ts_note");
			messageParam.setMsgType("system");
			sendMessageUtil.sendMessage(messageParam);
			log.info("系统通知发送成功，接收人: {}", sysUser.getUsername());
		} catch (Exception e) {
			log.error("发送系统通知失败", e);
		}
	}

}