package com.dayou.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.UUID;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.dayou.bo.ReportNounBO;
import com.dayou.bo.RichObject;
import com.dayou.common.BaseEntity;
import com.dayou.configuration.DfsConfig;
import com.dayou.dto.SectionTitleDTO;
import com.dayou.entity.ReportHeadline;
import com.dayou.entity.ReportMain;
import com.dayou.entity.ReportSection;
import com.dayou.enums.ReportNounsEnum;
import com.dayou.enums.ReportStatus;
import com.dayou.enums.ReportTypeEnum;
import com.dayou.exception.ErrorCode;
import com.dayou.mapper.ReportMainMapper;
import com.dayou.mapper.ReportSectionMapper;
import com.dayou.service.IReportHeadlineService;
import com.dayou.service.IReportMainService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dayou.service.IReportNounService;
import com.dayou.service.IReportSectionService;
import com.dayou.utils.*;
import com.dayou.vo.ReportMainVO;
import com.dayou.vo.ReportSectionTreeVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;

import java.util.*;
import java.util.stream.Collectors;

import org.springframework.transaction.annotation.Transactional;

import static com.dayou.common.Constants.*;

/**
 * <p>
 * 报告主表 服务实现类
 * </p>
 *
 * @author wucl
 * @since 2023-08-29
 */
@Service
public class ReportMainServiceImpl extends ServiceImpl<ReportMainMapper, ReportMain> implements IReportMainService {

    @Autowired
    private IReportHeadlineService reportHeadlineService;

    @Autowired
    private IReportSectionService reportSectionService;

    @Autowired
    private ReportMainMapper reportMainMapper;

    @Autowired
    private DfsConfig dfsConfig;

    @Autowired
    private IReportNounService reportNounService;

    @Autowired
    private ReportSectionMapper reportSectionMapper;

    @Override
    @SuppressWarnings("unchecked")
    public Page<ReportMainVO> selectPage(Page page, ReportMainVO reportMain){
        return reportMainMapper.getPage(page,reportMain);
    }


    @Override
    public ReportMainVO detail(Long id){
        ReportMain report = this.getById(id);
        String reportParams = report.getReportParams();
        Map<String, List<ReportNounBO>> reportNouns = JSON.parseObject(reportParams,
                new TypeReference<Map<String, List<ReportNounBO>>>() {});
        ReportMainVO reportMainVO = new ReportMainVO();
        reportMainVO.setId(report.getId());
        reportMainVO.setReportNouns(reportNouns);
        return reportMainVO;
    }

    @Transactional
    @Override
    public Boolean add(ReportMain reportMain){
        reportMain.setReportKey(UUID.fastUUID().toString(true));
        Long currentUserId = LoginContext.getCurrentUserId();
        reportMain.setUserId(currentUserId);
        reportMain.setTitle(reportMain.getPrefix()+DateUtils.dateTimeNow());
        String reportType = reportMain.getReportType();
        Long id = reportHeadlineService.getOne(new LambdaQueryWrapper<ReportHeadline>().select(BaseEntity::getId)
                .eq(ReportHeadline::getPlaceholder, reportType)).getId();
        reportMain.setHeadlineRootId(id);
        List<ReportNounBO> nouns = reportNounService.getListByType(reportType);
        Map<String,List<ReportNounBO>> nounsMap = new HashMap<>();
        nounsMap.put(ReportNounsEnum.COMMON.getCate(),nouns);
        reportMain.setReportParams(JSON.toJSONString(nounsMap));
        this.save(reportMain);

        List<ReportSection> reportSections = null ;
        List<ReportHeadline> headlines = reportHeadlineService.getHeadlinesByType(reportType);
        Long reportId = reportMain.getId();
        switch (ReportTypeEnum.valueOf(reportType)) {
            case LAND_CITY_PRICE:
                String mainObject = reportMain.getMainObject();
                reportSections = headlines.stream().map(x -> {
                    ReportSection reportSection = new ReportSection();
                    reportSection.setReportId(reportId);
                    reportSection.setUserId(currentUserId);
                    reportSection.setHeadlineId(x.getId());
                    reportSection.setHeadlineName(x.getHeadlineNum()+x.getHeadline().replaceAll(MAIN_OBJECT,mainObject));
                    return reportSection;
                }).collect(Collectors.toList());
                break;
            default:
                reportSections = headlines.stream().map(x -> {
                    ReportSection reportSection = new ReportSection();
                    reportSection.setReportId(reportId);
                    reportSection.setUserId(currentUserId);
                    reportSection.setHeadlineId(x.getId());
                    reportSection.setHeadlineName(x.getHeadlineNum()+x.getHeadline());
                    return reportSection;
                }).collect(Collectors.toList());
                break;
        }
        return reportSectionService.saveBatch(reportSections);
    }

    @Override
    public Boolean update(ReportMain reportMain){
        return  this.updateById(reportMain);
    }

    @Override
    public Boolean delete(Long id){
        //逻辑删除
        return this.removeById(id);
    }

    @Override
    public List<SectionTitleDTO> getReportMainSection(Long reportId) {
        return reportMainMapper.getReportMainSection(reportId);
    }

    @Override
    public Boolean generateReport(Long id) throws Exception {
        ReportMainVO reportMainVO = reportMainMapper.getReportMainVO(id);
        RichObject richObject = reportMainMapper.getFtlConfig(reportMainVO.getPlaceholder());
        List<SectionTitleDTO> sections = this.getReportMainSection(id);
        Map<String, String> collect = sections.stream().collect(Collectors.toMap(SectionTitleDTO::getTitle, SectionTitleDTO::getSection));
        HashMap<String, String> data = new HashMap();
        Map<String, List<ReportNounBO>> reportNouns = JSON.parseObject(reportMainVO.getReportParams(),
                new TypeReference<Map<String, List<ReportNounBO>>>() {});
        reportNouns.forEach((k,v)->{
            v.stream().forEach(x->{
                if (x.getValue()==null){
                    ErrorCode.throwBusinessException(ErrorCode.CUSTOM_ERROR,x.getName()+"未设置替换值。");
                }
                data.put(x.getPlaceholder(),x.getValue());
            });
        });
        List<RichHtmlHandler> richHtmlHandlerList = new ArrayList<RichHtmlHandler>();
        String path = dfsConfig.getPath();
        String domainName = dfsConfig.getDomainName();
        for (Map.Entry<String,String> map : collect.entrySet()){
            richObject.setHtml(map.getValue());
            richObject.setIsWebAppliction(true);
            richObject.setPath(dfsConfig.getPath());
            richObject.setDomainName(dfsConfig.getDomainName());
            RichHtmlHandler richHtmlHandler = WordGeneratorWithFreemarker.createRichHtmlHandler(richObject);
            richHtmlHandlerList.add(richHtmlHandler);
            data.put(map.getKey(), richHtmlHandler.getHandledDocBodyBlock());
        }
        data.put("imagesXmlHrefString", WordGeneratorWithFreemarker.getXmlImgHref(richHtmlHandlerList));
        data.put("imagesBase64String", WordGeneratorWithFreemarker.getImagesBase64String(richHtmlHandlerList));
        String referencePath = dfsConfig.getDomain()+FileUploadUtils.generateDocName();
//server
        String fileUploadPath = "/opt"+referencePath;
        String templatePath = richObject.getFtlPath();
        String templateNamePath = richObject.getFtlName();

//location
//        String fileUploadPath = "F:\\risk.docx";
//        String templatePath = Class.class.getResource("/ftl/land").getPath();
//        String templateNamePath = Class.class.getResource("/ftl/land/risk.ftl").getPath();

        WordGeneratorWithFreemarker.createDoc(templatePath,templateNamePath,data,fileUploadPath);
        return this.update(new LambdaUpdateWrapper<ReportMain>().eq(BaseEntity::getId,id)
                .set(ReportMain::getUrl,referencePath).set(ReportMain::getStatus, ReportStatus.审核中));

    }

    @Override
    public Boolean updateNouns(ReportMainVO reportMain) {
        Map<String, List<ReportNounBO>> reportNouns = reportMain.getReportNouns();
        Long id = reportMain.getId();
        String reportParams = JSON.toJSONString(reportNouns);
        boolean update = this.update(new LambdaUpdateWrapper<ReportMain>().set(ReportMain::getReportParams, reportParams).eq(BaseEntity::getId, id));
        return update;
    }

    @Override
    public List<ReportSectionTreeVO> getReportHeadlineTree(Long id) {
        ReportMain reportMain = this.getById(id);
        List<ReportSectionTreeVO> list = reportSectionMapper.getReportSectionTree(id);
        return (List<ReportSectionTreeVO>) TreeUtil.buildTree(list,reportMain.getHeadlineRootId());
    }
}
