package com.cmeeting.service.impl;

import cn.chatbot.meeting.DebugOutputTool;
import cn.chatbot.meeting.LLMConfig;
import cn.chatbot.meeting.LLMResult;
import cn.chatbot.meeting.MeetingProcess;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.IoUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cmeeting.ad.entity.RobotSecurityUser;
import com.cmeeting.ad.entity.SysDept;
import com.cmeeting.ad.entity.SysUserSync;
import com.cmeeting.ad.util.SecurityUtil;
import com.cmeeting.exception.RobotBaseException;
import com.cmeeting.mapper.primary.RecordTemplatePermissionMapper;
import com.cmeeting.mapper.primary.SysUserSyncMapper;
import com.cmeeting.pojo.MeetingInfo;
import com.cmeeting.pojo.MeetingRecordTemplate;
import com.cmeeting.pojo.RecordTemplatePermission;
import com.cmeeting.service.MeetingInfoService;
import com.cmeeting.service.MeetingRecordTemplateService;
import com.cmeeting.service.RecordTemplatePermissionService;
import com.cmeeting.util.AESUtils;
import com.cmeeting.util.MinioUtils;
import com.cmeeting.vo.RecordTemplateVO;
import com.deepoove.poi.XWPFTemplate;
import com.fasterxml.jackson.core.JsonProcessingException;
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.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

@Service
@Slf4j
public class RecordTemplatePermissionServiceImpl extends ServiceImpl<RecordTemplatePermissionMapper, RecordTemplatePermission>  implements RecordTemplatePermissionService {

    @Resource
    private MeetingRecordTemplateService recordTemplateService;
    @Resource
    private MeetingInfoService meetingInfoService;
    @Resource
    private SysUserSyncMapper sysUserSysMapper;
    @Resource
    private MinioUtils minioUtils;
    @Value(value = "${llm.api-addr}")
    private String llmApiAddr;
    @Value(value = "${llm.api-model}")
    private String llmModel;
    @Value(value = "${llm.api-token}")
    private String llmToken;
    @Value(value = "${llm.api-max-tokens}")
    private Integer llmMaxTokens;
    @Value("${aec.key}")
    public String aesKey;

    /**
     * 授权
     * @param vo
     */
    @Override
    public boolean auth(RecordTemplateVO.TemplatePermissionVO vo) {
        List<RecordTemplateVO.PermissionItem> permissionItems = vo.getPermissionItems();
        if(vo.getTemplateId() == null){
            return false;
        }
        MeetingRecordTemplate template = recordTemplateService.getById(vo.getTemplateId());
        if(template == null){
            throw new RuntimeException("模板不存在");
        }
        List<RecordTemplatePermission> permissions = new ArrayList<>();
        LocalDateTime now = LocalDateTime.now();
        for (RecordTemplateVO.PermissionItem permissionItem : permissionItems) {
            RecordTemplatePermission permission = RecordTemplatePermission.builder()
                    .templateId(vo.getTemplateId())
                    .templateType(template.getType())
                    .relType(permissionItem.getRelType())
                    .relId(permissionItem.getRelId())
                    .createTime(now)
                    .build();
            permissions.add(permission);
        }
        //对比数据库中已保存的权限信息，删除本次授权不包含的对象权限
        List<String> permissionRelIds = permissions.stream().map(RecordTemplatePermission::getRelId).collect(Collectors.toList());
        List<RecordTemplatePermission> savedPermissions = baseMapper.selectList(new LambdaQueryWrapper<RecordTemplatePermission>().eq(RecordTemplatePermission::getTemplateId, template.getId()));
        //过滤出需要删除的权限
        List<Integer> deletablePermissionIds = savedPermissions.stream()
                .filter(item -> !permissionRelIds.contains(item.getRelId())).map(RecordTemplatePermission::getId).collect(Collectors.toList());
        if(!CollectionUtils.isEmpty(deletablePermissionIds)){
            baseMapper.deleteBatchIds(deletablePermissionIds);
        }
        if(!CollectionUtils.isEmpty(permissions)){
            baseMapper.batchInsert(permissions);
        }
        return true;
    }

    /**
     * 查询某个模板已经授权的人员或部门
     * @param vo
     * @return
     */
    @Override
    public List<RecordTemplateVO.PermissionItem> authList(RecordTemplateVO.TemplateAuthVO vo) {
        RobotSecurityUser user = SecurityUtil.getUser();
        List<RecordTemplatePermission> permissions = baseMapper.selectList(
                new LambdaQueryWrapper<RecordTemplatePermission>()
                        .eq(RecordTemplatePermission::getTemplateId,vo.getTemplateId()));
        List<RecordTemplateVO.PermissionItem> permissionItems = new ArrayList<>();
        if(!CollectionUtils.isEmpty(permissions)){
            List<SysUserSync> simpleUserList = sysUserSysMapper.getSimpleUserList();
            Map<String, String> simpleUserMap = CollectionUtils.isEmpty(simpleUserList)
                    ? new HashMap<>() : simpleUserList.stream().collect(Collectors.toMap(SysUserSync::getUserId, SysUserSync::getName));
            List<SysDept> simpleDeptList = sysUserSysMapper.getSimpleDeptList();
            Map<String, String> simpleDeptMap = CollectionUtils.isEmpty(simpleDeptList)
                    ? new HashMap<>() : simpleDeptList.stream().collect(Collectors.toMap(SysDept::getDeptId, SysDept::getName));
            for (RecordTemplatePermission permission : permissions) {
                String relName = "1".equals(permission.getRelType()) && simpleDeptMap.containsKey(permission.getRelId())
                        ? simpleDeptMap.get(permission.getRelId())
                        : "2".equals(permission.getRelType()) && simpleUserMap.containsKey(permission.getRelId())
                        ? simpleUserMap.get(permission.getRelId()) : permission.getRelId();
                RecordTemplateVO.PermissionItem permissionItem = RecordTemplateVO.PermissionItem.builder()
                        .relId(permission.getRelId())
                        .relType(permission.getRelType())
                        .relName(relName).build();
                permissionItems.add(permissionItem);
            }

        }
        return permissionItems;
    }

    /**
     * 模板测试效果
     * @param file 用户自主上传的转录文件
     * @param meetingInstId 历史会议主键id
     * @return
     */
    @Override
    public String testGenerate(MultipartFile file, Integer meetingInstId, String prompt) {
        if((file == null || file.isEmpty() || file.getSize() == 0) && meetingInstId == null){
            throw new RobotBaseException("请提供转录文件");
        }
        //纪要模板
        String textContent;
        String meetingDate = null;
        String participantNames = null;
        if(meetingInstId != null){
            MeetingInfo meetingInfo = meetingInfoService.getById(meetingInstId);
            if(meetingInfo == null) throw new RobotBaseException("历史会议不存在！");
            String recordContent = meetingInfo.getRecordContent();
            if(StringUtils.isEmpty(recordContent)) throw new RobotBaseException("历史会议的转录文件为空，请核实");
//            try {
//                textContent = minioUtils.getFileText(recordContent);
            InputStream inputStream = minioUtils.getFile(recordContent);
                // 解密
            textContent = AESUtils.decrypt(IoUtil.read(inputStream, StandardCharsets.UTF_8), aesKey);
//            } catch (IOException e) {
//                throw new RobotBaseException("历史会议的转录文件内容读取失败！");
//            }
            meetingDate = meetingInfo.getStartTime().toLocalDate().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
            participantNames = meetingInfo.getParticipantUsers();
        }else{
            try{
                byte[] bytes = file.getBytes();
                textContent = new String(bytes);
            }catch (Exception e){
                throw new RobotBaseException("上传的转录文件内容读取失败！");
            }
        }

        LLMConfig baseLLM = new LLMConfig(llmModel,
                llmApiAddr,
                "Bearer " + llmToken,
                llmMaxTokens);
        LLMResult llmResult = MeetingProcess.processMeeting(prompt, textContent, meetingDate, participantNames, baseLLM, new ArrayList<>());
        DebugOutputTool.println(llmResult.respond);

        //去除内容中除了xml内容以外其他的信息，格式化xml
        String xml = extractXmlFromMarkdown(llmResult.respond);
        return convertXmlToJSON(xml);
    }

    @Override
    public void testMinutesExport(String recordJson,Integer meetingInstId, Integer id, HttpServletResponse response) {
        try {
            String xml = convertJSONToXml(recordJson);
            Map<String, Object> dataModel = convertXmlToMap(xml);
            if(meetingInstId != null){
                //追加参会人员信息
                MeetingInfo meetingInfo = meetingInfoService.getById(meetingInstId);
                Map<String,Object> participantsMap = new ConcurrentHashMap<>();
                String meetingDate = meetingInfo.getStartTime().toLocalDate().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
                participantsMap.put("meeting_date",meetingDate);
                participantsMap.put("meeting_location","线上腾讯会议");
                participantsMap.put("meeting_participants", meetingInfo.getParticipantUsers());
                participantsMap.put("meeting_host",meetingInfo.getHost());
                dataModel.putAll(participantsMap);
            }


            if(id == null){
                throw new RobotBaseException("请指定用于生成纪要的模板");
            }
            MeetingRecordTemplate recordTemplate = recordTemplateService.getById(id);
            if(recordTemplate == null){
                throw new RobotBaseException("纪要模板不存在！");
            }
            //纪要模板
            String templateIndex = recordTemplate.getTemplate();

            String fileName = String.format("会议纪要效果_%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"));
            XWPFTemplate template;
            try (InputStream is = minioUtils.getFile(templateIndex); 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();
        }
    }

    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;
    }

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

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

        // 先将 XML 读取为 Map
        Map<?, ?> xmlMap = null;
        try {
            xmlMap = xmlMapper.readValue(xml, Map.class);
        } catch (JsonProcessingException e) {
            throw new RobotBaseException(e.getMessage());
        }

        // 转换为更标准的 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();
            //取出正确的value并设置
            String realValue = String.valueOf(value.get("")).replaceAll("^\\n+","");
            //内容段首移除换行，段末追加换行(会议名称结尾不换行
            entry.setValue(realValue.endsWith("\n") || "meeting_name".equals(entry.getKey()) || "meeting_purpose".equals(entry.getKey()) ? realValue : realValue + "\n");
        }
        return map;
    }

    /**
     * markdown转xml
     * @param markdown
     * @return
     */
    private String extractXmlFromMarkdown(String markdown) {
        StringBuffer sb = null;
        try {
            int start = markdown.indexOf("<");
            int end = markdown.lastIndexOf(">") + 1;
            sb = new StringBuffer();
            sb.append("<root>");
            String xml = markdown.substring(start, end).trim().replaceAll("\n\n","\n");
            sb.append(xml);
            sb.append("</root>");
        } catch (Exception e) {
            log.info("markdown转xml，markdown->{}",markdown);
        }
        return sb.toString();
    }

    private String convertJSONToXml(String json) {
        JSONArray jsonArray = JSON.parseArray(json);
        StringBuilder xmlBuilder = new StringBuilder();

        xmlBuilder.append("<root>");
        for (int i = 0; i < jsonArray.size(); i++) {
            JSONObject jsonObj = jsonArray.getJSONObject(i);

            String key = jsonObj.getString("key");
            String label = jsonObj.getString("keyName");
            String value = jsonObj.getString("value");

            xmlBuilder.append(String.format("<%s label=\"%s\">%s</%s>",
                    key, label, value, key));
        }
        xmlBuilder.append("</root>");

        return xmlBuilder.toString();
    }
}