package com.cmeeting.controller;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.IoUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.cmeeting.ad.entity.RobotSecurityUser;
import com.cmeeting.ad.util.SecurityUtil;
import com.cmeeting.annotation.OperLog;
import com.cmeeting.config.StatisticsEmailPushProperties;
import com.cmeeting.constant.DeptCollect;
import com.cmeeting.email.EmailSender;
import com.cmeeting.exception.RobotBaseException;
import com.cmeeting.mapper.primary.MeetingRecordTemplateMapper;
import com.cmeeting.mapper.primary.UserIdMapper;
import com.cmeeting.pojo.MeetingInfo;
import com.cmeeting.pojo.MeetingRecordTemplate;
import com.cmeeting.service.MeetingInfoService;
import com.cmeeting.util.AESUtils;
import com.cmeeting.util.MinioUtils;
import com.cmeeting.util.R;
import com.cmeeting.vo.EmailPush;
import com.cmeeting.vo.EmailStatisticsVo;
import com.cmeeting.vo.MeetingInfoVO;
import com.cmeeting.vo.StatisticsEmailPush;
import com.deepoove.poi.XWPFTemplate;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ClassPathResource;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
@RestController
@RequestMapping("/meetingInfo")
public class MeetingInfoController {

    @Resource
    private MeetingInfoService meetingInfoService;
    @Resource
    private MinioUtils minioUtils;
    @Resource
    private EmailSender emailSender;
    @Resource
    private MeetingRecordTemplateMapper meetingRecordTemplateMapper;
    @Resource
    private UserIdMapper userIdMapper;
    @Value(value = "${permission.applicationId}")
    private String permissionApplicationId;
    @Value(value = "${userAdmin.file-download-path}")
    private String fileDownloadPath;
    @Value("${aec.key}")
    public String aesKey;

    @OperLog(location = "历史会议纪要详情页面", operation = "修改会议纪要")
    @PostMapping("/updateRecordXml")
    public R updateRecordXml(@RequestBody MeetingInfoVO vo) {
        boolean save = meetingInfoService.updateRecordXml(vo);
        return R.ok(save);
    }

    /**
     * 重新生成
     *
     * @param vo
     * @return
     */
    @OperLog(location = "历史会议纪要详情页面", operation = "重新生成会议纪要")
    @PostMapping("/regenerateXml")
    public R regenerateXml(@RequestBody MeetingInfoVO vo) {
        boolean isSuccess = meetingInfoService.regenerateXml(vo);
        return R.ok(isSuccess);
    }

    @PostMapping("/list")
    public R list(@RequestBody MeetingInfoVO vo) {
        IPage<MeetingInfo> page = meetingInfoService.getPage(vo);
        return R.ok(page);
    }

    @PostMapping("/detail")
    public R detail(@RequestBody @Validated MeetingInfoVO vo) {
        RobotSecurityUser user = SecurityUtil.getUser();
        MeetingInfo meetingInfo = meetingInfoService.getById(vo.getId());
        BeanUtils.copyProperties(meetingInfo, vo);
        vo.setUserId(user.getId());
        vo.setApplicationId(permissionApplicationId);
        String recordXml = vo.getRecordXml();
        String recordContent = vo.getRecordContent();
        try {
            if (StringUtils.isNotEmpty(recordXml)) {
                //xml转json，用于前端的表单回显
                InputStream inputStream = minioUtils.getFile(meetingInfo.getRecordXml());
                // 解密
                String xml = AESUtils.decrypt(IoUtil.read(inputStream, StandardCharsets.UTF_8), aesKey);

                String json = convertXmlToJSON(xml);
                vo.setRecordJson(json);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            if(StringUtils.isNotEmpty(recordContent)){
                InputStream inputStream = minioUtils.getFile(meetingInfo.getRecordContent());
                // 解密
                String content = AESUtils.decrypt(IoUtil.read(inputStream, StandardCharsets.UTF_8), aesKey);
                vo.setRecordContent(content);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return R.ok(vo);
    }

    /**
     * 导出转写原文
     */
    @OperLog(location = "历史会议纪要详情页面", operation = "导出转写原文")
    @PostMapping("/exportMeetingRecord")
    public void exportMeetingRecord(@RequestBody MeetingInfoVO vo, HttpServletResponse response) {
        try {
            MeetingInfo meetingInfo = meetingInfoService.getById(vo.getId());
            InputStream inputStream = minioUtils.getFile(meetingInfo.getRecordContent());
            // 解密
            String content = AESUtils.decrypt(IoUtil.read(inputStream, StandardCharsets.UTF_8), aesKey);

            String fileName = String.format(meetingInfo.getSubject() + "_转写原文_%s.docx", DateUtil.today());
            response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
            response.setCharacterEncoding("utf-8");
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "utf8"));
            try (XWPFDocument document = new XWPFDocument(); OutputStream os = response.getOutputStream()) {
                // 将文本按行分割并逐行添加到 Word 文档
                String[] lines = content.split("\\r?\\n");
                for (String line : lines) {
                    XWPFParagraph paragraph = document.createParagraph();
                    XWPFRun run = paragraph.createRun();
                    run.setText(line);
                }

                // 输出文档
                document.write(os);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        } catch (Exception e) {
            response.reset();
            response.setContentType("text/plain");
            response.setCharacterEncoding("utf-8");
            e.printStackTrace();
        }
    }

    /**
     * 导出会议纪要（本地下载）
     */
    @OperLog(location = "历史会议纪要详情页面", operation = "导出会议纪要（本地下载）")
    @PostMapping("/downloadMeetingMinutes")
    public void downloadMeetingMinutes(@RequestBody MeetingInfoVO vo, HttpServletResponse response) {
        try {
            MeetingInfo meetingInfo = meetingInfoService.getById(vo.getId());
            InputStream inputStream = minioUtils.getFile(meetingInfo.getRecordXml());
            // 解密
            String xml = AESUtils.decrypt(IoUtil.read(inputStream, StandardCharsets.UTF_8), aesKey);

            Map<String, Object> dataModel = convertXmlToMap(xml);
            //追加参会人员信息
            Map<String, Object> participantsMap = new ConcurrentHashMap<>();
            DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd");
            String meetingDate = meetingInfo.getStartTime().toLocalDate().format(df);
            participantsMap.put("meeting_date", meetingDate);
            participantsMap.put("meeting_location", "线上腾讯会议");
            participantsMap.put("meeting_participants", meetingInfo.getParticipantUsers());
            participantsMap.put("meeting_host", meetingInfo.getHost());

            dataModel.putAll(participantsMap);
            MeetingRecordTemplate meetingRecordTemplate = meetingRecordTemplateMapper.selectById(meetingInfo.getTemplateId());
            if (meetingRecordTemplate == null) {
                meetingRecordTemplate = meetingRecordTemplateMapper.selectById(1);
//                throw new RobotBaseException("该会议使用的模板已被删除!");
            }
            DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyyMMdd");
            String fileName = String.format(meetingInfo.getSubject() + "会议纪要_%s.docx", fmt.format(meetingInfo.getStartTime()));
            response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
            response.setCharacterEncoding("utf-8");
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "utf8"));
            XWPFTemplate template;
            try (InputStream is = minioUtils.getFile(meetingRecordTemplate.getTemplate()); OutputStream os = response.getOutputStream()) {
                template = XWPFTemplate.compile(is).render(dataModel);
                template.write(os);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        } catch (Exception e) {
            response.reset();
            response.setContentType("text/plain");
            response.setCharacterEncoding("utf-8");
            e.printStackTrace();
        }
    }

    /**
     * 导出会议纪要（推送邮件）
     */
    @OperLog(location = "历史会议纪要详情页面", operation = "导出会议纪要成文件（推送邮件）")
    @PostMapping("/pushMeetingMinutes")
    public R exportMeetingMinutes(@RequestBody MeetingInfoVO vo, HttpServletResponse response) {
        try {
            MeetingInfo meetingInfo = meetingInfoService.getById(vo.getId());
            InputStream inputStream = minioUtils.getFile(meetingInfo.getRecordXml());
            // 解密
            String xml = AESUtils.decrypt(IoUtil.read(inputStream, StandardCharsets.UTF_8), aesKey);
            Map<String, Object> dataModel = convertXmlToMap(xml);
            //追加参会人员信息
            Map<String, Object> participantsMap = new ConcurrentHashMap<>();
            DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd");
            String meetingDate = meetingInfo.getStartTime().toLocalDate().format(df);
            participantsMap.put("meeting_date", meetingDate);
            participantsMap.put("meeting_location", "线上腾讯会议");
            participantsMap.put("meeting_participants", meetingInfo.getParticipantUsers());
            participantsMap.put("meeting_host", meetingInfo.getHost());

            dataModel.putAll(participantsMap);
            MeetingRecordTemplate meetingRecordTemplate = meetingRecordTemplateMapper.selectById(meetingInfo.getTemplateId());
            if (meetingRecordTemplate == null) {
                meetingRecordTemplate = meetingRecordTemplateMapper.selectById(1);
//                throw new RobotBaseException("该会议使用的模板已被删除!");
            }
            XWPFTemplate template;
            byte[] meetingMinutesBytes;
            try (InputStream is = minioUtils.getFile(meetingRecordTemplate.getTemplate()); ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
                template = XWPFTemplate.compile(is).render(dataModel);
                template.write(baos);
                meetingMinutesBytes = baos.toByteArray();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            List<EmailPush.Attachment> attachments = new ArrayList<>();

            DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyyMMdd");
            EmailPush.Attachment attachment = EmailPush.Attachment.builder().name(meetingInfo.getSubject() + "会议纪要_" + fmt.format(meetingInfo.getStartTime())).bytes(meetingMinutesBytes).build();
            attachments.add(attachment);

            org.springframework.core.io.Resource resource = new ClassPathResource("static/Cmeeting会议助手使用手册.pdf");
            byte[] meetingMinutesBytes2 = IOUtils.toByteArray(resource.getInputStream());
            EmailPush.Attachment attachment2 = EmailPush.Attachment.builder().name("Cmeeting会议助手使用手册.pdf").bytes(meetingMinutesBytes2).build();
            attachments.add(attachment2);

            String hostUid = meetingInfo.getHostUid();
            String userCode = userIdMapper.getWidByTid(hostUid);
            EmailPush emailPushBuilder = EmailPush.builder()
                    .toEmail(meetingInfo.getEmail())
                    .meetingId(meetingInfo.getMeetingId())
                    .meetingRecordId(meetingInfo.getMeetingRecordId())
                    .attachments(attachments)
                    .subject(meetingInfo.getSubject())
                    .meetingInstanceId(meetingInfo.getId())
                    .subMeetingId(meetingInfo.getSubMeetingId())
                    .toUserCode(userCode)
                    .toUser(meetingInfo.getHost())
                    .emailPushAccess(meetingInfo.getEmailPushAccess())
                    .build();
            emailSender.sendEmailWithAttachment(emailPushBuilder);
            return R.ok("发送纪要邮件成功");
        } catch (Exception e) {
            response.reset();
            response.setContentType("text/plain");
            response.setCharacterEncoding("utf-8");
            e.printStackTrace();
            return R.error("发送纪要邮件失败");
        }
    }

    public static Map<String, Object> convertXmlToMap(String xml) throws Exception {

        XmlMapper xmlMapper = new XmlMapper();
        ObjectMapper objectMapper = new ObjectMapper();

        // 先将 XML 读取为 Map
        Map<?, ?> xmlMap = xmlMapper.readValue(xml, Map.class);

        // 转换为更标准的 Map<String, Object>
        Map<String, Object> map = objectMapper.convertValue(xmlMap, Map.class);
        //特殊处理map格式
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            Map<String, Object> value = (Map<String, Object>) entry.getValue();
            Object realValue = value.get("");
            entry.setValue(realValue);
        }
        return map;
    }

    private String convertXmlToJSON(String xml) {
        String json;
        try {
            XmlMapper xmlMapper = new XmlMapper();
            JsonNode rootNode = xmlMapper.readTree(xml.getBytes());

            // 正确获取节点和属性的方式
            List<Map> list = new ArrayList<>();
            Iterator<String> iterator = rootNode.fieldNames();
            while (iterator.hasNext()) {
                String tagName = iterator.next();
                JsonNode subNode = rootNode.path(tagName);
                String displayName = subNode.path("label").asText();
                String content = subNode.path("").asText();
                list.add(new HashMap() {{
                    put("key", tagName);
                    put("keyName", displayName);
                    put("value", content);
                }});
            }
            // 构建JSON对象
            ObjectMapper jsonMapper = new ObjectMapper();
            json = jsonMapper.writeValueAsString(list);
        } catch (IOException e) {
            log.error(e.getMessage());
            throw new RuntimeException(e.getMessage());
        }
        return json;
    }


    @PostMapping("/statistics")
    public void statisticsEmail(@RequestBody EmailStatisticsVo vo, HttpServletResponse response) {
        meetingInfoService.statisticsEmail(vo.getType(), vo.getStartTime(), vo.getEndTime(), response, DeptCollect.DEPT_MAP);
    }


    @PostMapping("/statisticsByDept")
    public void statisticsByDept(@RequestBody EmailStatisticsVo vo, HttpServletResponse response) throws IOException {
        String title = String.format("会议纪要推送统计表_%s-%s", DateUtil.format(vo.getStartTime(), "yyyyMMdd"), DateUtil.format(vo.getEndTime(), "yyyyMMdd"));
        String fileName = String.format("%s.xlsx", title);
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
        response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "utf8"));
        meetingInfoService.statisticsEmail(title, vo.getStartTime(), vo.getEndTime(), response.getOutputStream(), DeptCollect.DEPT_MAP);
    }

    @Resource
    private StatisticsEmailPushProperties statisticsEmailPushProperties;

    @Value(value = "${tencent.base-save-path}")
    private String savePath;
    /**
     * 每天两小时发送会议统计邮件测试接口
     */
    @GetMapping("/emailStatisticsPushTest")
    public void emailStatisticsPush() {
        log.info("推送统计邮件开始！");
        List<StatisticsEmailPush.Attachment> attachments = new ArrayList<>();

        Date date = new Date();

        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.HOUR_OF_DAY, 1); // 增加 1 小时
        Date newDate = calendar.getTime(); // 返回增加后的 Date 对象
        String subject = "会议纪要推送记录-" + new SimpleDateFormat("yyyyMMdd HH").format(newDate) + ":00";
        String content;
        if (CollUtil.isEmpty(statisticsEmailPushProperties.getToEmails())) {
            log.error("收件人为空！");
            return;
        }
        File file = new File(savePath + subject + ".xlsx");

        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        SimpleDateFormat simpleDateFormat1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        try {
            boolean b = meetingInfoService.statisticsEmail(subject, simpleDateFormat1.parse(simpleDateFormat.format(date) + " 00:00:00"),
                    simpleDateFormat1.parse(simpleDateFormat.format(date) + " 23:59:59"), new FileOutputStream(file), DeptCollect.DEPT_MAP);
            if (b) {
                content = "<p data-olk-copy-source=\\\"MessageBody\\\">Dear all：<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;附件为今天Cmeeting会议纪要生成和发送情况，烦请查收。</p>";
                StatisticsEmailPush.Attachment attachment = new StatisticsEmailPush.Attachment();
                attachment.setName(subject);
                attachment.setBytes(IOUtils.toByteArray(Files.newInputStream(file.toPath())));
                attachments.add(attachment);
            } else {
                content = "<p data-olk-copy-source=\\\"MessageBody\\\">Dear all：<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;今天到目前为止没有会议。</p>";
            }
            StatisticsEmailPush emailPushBuilder = StatisticsEmailPush.builder()
                    .toEmails(statisticsEmailPushProperties.getToEmails())
                    .attachments(attachments)
                    .subject(subject)
                    .content(content)
                    .build();
            emailSender.emailStatisticsPush(emailPushBuilder);
        } catch (IOException | ParseException e) {
            throw new RuntimeException(e);
        } finally {
            file.delete();
        }
    }



}
