package com.qmth.distributed.print.business.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qmth.distributed.print.business.bean.examRule.CodeName;
import com.qmth.distributed.print.business.bean.examRule.CodeNameEnable;
import com.qmth.distributed.print.business.bean.examRule.CodeNameEnableRate;
import com.qmth.distributed.print.business.bean.result.TemplatePrintInfoResult;
import com.qmth.distributed.print.business.entity.BasicExamRule;
import com.qmth.distributed.print.business.entity.BasicTemplate;
import com.qmth.distributed.print.business.mapper.BasicTemplateMapper;
import com.qmth.distributed.print.business.service.*;
import com.qmth.distributed.print.business.util.PdfFillUtils;
import com.qmth.teachcloud.common.bean.dto.DataPermissionRule;
import com.qmth.teachcloud.common.contant.SystemConstant;
import com.qmth.teachcloud.common.entity.BasicAttachment;
import com.qmth.teachcloud.common.entity.BasicPrintConfig;
import com.qmth.teachcloud.common.entity.SysUser;
import com.qmth.teachcloud.common.enums.ClassifyEnum;
import com.qmth.teachcloud.common.enums.EnumResult;
import com.qmth.teachcloud.common.enums.ExceptionResultEnum;
import com.qmth.teachcloud.common.enums.UploadFileEnum;
import com.qmth.teachcloud.common.service.BasicAttachmentService;
import com.qmth.teachcloud.common.service.BasicRoleDataPermissionService;
import com.qmth.teachcloud.common.service.FileUploadService;
import com.qmth.teachcloud.common.service.TeachcloudCommonService;
import com.qmth.teachcloud.common.util.ServletUtil;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.File;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 通用模板 服务实现类
 * </p>
 *
 * @author xf
 * @since 2021-03-23
 */
@Service
public class BasicTemplateServiceImpl extends ServiceImpl<BasicTemplateMapper, BasicTemplate> implements BasicTemplateService {

    @Autowired
    private BasicAttachmentService basicAttachmentService;

    @Resource
    TeachcloudCommonService teachcloudCommonService;

    @Resource
    BasicTemplateMapper basicTemplateMapper;

    @Resource
    BasicPrintConfigService basicPrintConfigService;

    @Resource
    private BasicRoleDataPermissionService basicRoleDataPermissionService;

    @Resource
    private BasicExamRuleService basicExamRuleService;

    @Resource
    private ExamPrintPlanService examPrintPlanService;
    @Resource
    private FileUploadService fileUploadService;

    @Override
    public IPage<BasicTemplate> list(Boolean enable, String name, Long startTime, Long endTime, Integer pageNumber, Integer pageSize) {
        Long schoolId = Long.valueOf(ServletUtil.getRequestHeaderSchoolId().toString());
        SysUser requestUser = (SysUser) ServletUtil.getRequestUser();
        DataPermissionRule dpr = basicRoleDataPermissionService.findDataPermission(schoolId, requestUser.getId(), ServletUtil.getRequest().getServletPath());
        return this.baseMapper.listPage(new Page<>(pageNumber, pageSize), schoolId, enable, SystemConstant.translateSpecificSign(name), startTime, endTime, dpr);
    }

    @Transactional
    @Override
    public boolean saveTemplate(String data) throws Exception {
        BasicTemplate template = JSON.parseObject(data, BasicTemplate.class);
        Long schoolId = Long.valueOf(ServletUtil.getRequestHeaderSchoolId().toString());
        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
        template.setSchoolId(schoolId);
        template.setOrgId(sysUser.getOrgId());
        QueryWrapper<BasicTemplate> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(BasicTemplate::getSchoolId, template.getSchoolId()).eq(BasicTemplate::getName, template.getName());
        BasicTemplate basicTemplate = this.getOne(queryWrapper);
        boolean isSuccess;
        // 新增
        if (Objects.isNull(template.getId())) {
            if (basicTemplate != null) {
                throw ExceptionResultEnum.ERROR.exception("模板名称已使用");
            }
            template.insertInfo(sysUser.getId());
        }
        // 修改
        else {
            if (basicTemplate != null) {
                if (basicTemplate.getId().longValue() != template.getId().longValue()) {
                    throw ExceptionResultEnum.ERROR.exception("模板名称已存在");
                }
                // 删除预览时生成的附件
                if (StringUtils.isNotBlank((basicTemplate.getPreviewPath()))) {
                    JSONObject jsonObject = JSON.parseObject(basicTemplate.getPreviewPath());
                    String type = jsonObject.getString(SystemConstant.TYPE);
                    if (Objects.nonNull(type) && type.equalsIgnoreCase(SystemConstant.LOCAL)) {
                        FileUtils.forceDelete(new File(jsonObject.getString(SystemConstant.PATH)));
                    }
                }
            }
            template.setPreviewPath(null);
            template.updateInfo(sysUser.getId());

            // 普通印品重新上传附件后，同是更新使用的附件ID
            basicPrintConfigService.updateAttachmentIdByTemplateId(template.getId(), template.getAttachmentId());
            examPrintPlanService.updateAttachmentIdByTemplateId(template.getId(), template.getAttachmentId());
        }
        return this.saveOrUpdate(template);
    }

    @Override
    public boolean enable(BasicTemplate template) {
        UpdateWrapper<BasicTemplate> updateWrapper = new UpdateWrapper<>();
        updateWrapper.lambda().set(BasicTemplate::getEnable, template.getEnable()).eq(BasicTemplate::getId, template.getId());
        return this.update(updateWrapper);
    }

    @Override
    public BasicTemplate getOne(Long id) {
        BasicTemplate basicTemplate = this.getById(id);
        if (basicTemplate.getAttachmentId() != null) {
            BasicAttachment basicAttachment = basicAttachmentService.getById(basicTemplate.getAttachmentId());
            if (basicAttachment == null) {
                throw ExceptionResultEnum.ERROR.exception("上传附件数据丢失，请重新上传");
            }
            String url = teachcloudCommonService.filePreview(basicAttachment.getPath());
            basicTemplate.setUrl(url);
        }

        if (basicTemplate.getClassify().equals(ClassifyEnum.SIGN) || basicTemplate.getClassify().equals(ClassifyEnum.PACKAGE)) {
            // 新添加的字段，在已经印品中无法显示和选择
            BasicExamRule basicExamRule = basicExamRuleService.getBySchoolId();

            JSONObject object = JSONObject.parseObject(basicTemplate.getDisplayRange());
            List<CodeNameEnable> displayRanges = JSONObject.parseArray(object.getString("basic"), CodeNameEnable.class);
            // 签到表
            if (basicTemplate.getClassify().equals(ClassifyEnum.SIGN)) {
                if (StringUtils.isBlank(basicExamRule.getSignScope())) {
                    throw ExceptionResultEnum.ERROR.exception("通用规则中签到表字段未配置");
                }
                // basic部分
                JSONObject signObject = JSONObject.parseObject(basicExamRule.getSignScope());
                List<CodeNameEnable> signBasicList = JSONObject.parseArray(signObject.getString("basic"), CodeNameEnable.class);
                for (CodeNameEnable jsonObject : signBasicList) {
                    Optional<CodeNameEnable> objectOptional = displayRanges.stream().filter(m -> m.getCode().equals(jsonObject.getCode())).findFirst();
                    if (objectOptional.isPresent()) {
                        jsonObject.setEnable(objectOptional.get().getEnable());
                    } else {
                        jsonObject.setEnable(false);
                    }
                }
                object.put("basic", signBasicList);

                // table部分
                List<CodeNameEnableRate> tableDisplayRanges = JSONObject.parseArray(object.getString("table"), CodeNameEnableRate.class);
                List<CodeNameEnableRate> signTableList = JSONObject.parseArray(signObject.getString("table"), CodeNameEnableRate.class);
                for (CodeNameEnableRate jsonObject : signTableList) {
                    Optional<CodeNameEnableRate> objectOptional = tableDisplayRanges.stream().filter(m -> m.getCode().equals(jsonObject.getCode())).findFirst();
                    if (objectOptional.isPresent()) {
                        jsonObject.setEnable(objectOptional.get().getEnable());
                        jsonObject.setRate(objectOptional.get().getRate());
                    } else {
                        jsonObject.setEnable(false);
                    }
                }
                Optional<CodeNameEnableRate> studentSign = tableDisplayRanges.stream().filter(m -> m.getCode().equals("studentSign")).findFirst();
                if (studentSign.isPresent()) {
                    signTableList.add(studentSign.get());
                } else {
                    CodeNameEnableRate codeNameEnableRate = new CodeNameEnableRate();
                    codeNameEnableRate.setCode("studentSign");
                    codeNameEnableRate.setName("签名");
                    codeNameEnableRate.setEnable(true);
                    codeNameEnableRate.setRate(20);
                    signTableList.add(codeNameEnableRate);
                }

                object.put("table", signTableList);
                basicTemplate.setDisplayRange(JSONObject.toJSONString(object));
            }

            // 卷袋贴
            if (basicTemplate.getClassify().equals(ClassifyEnum.PACKAGE)) {
                if (StringUtils.isBlank(basicExamRule.getPackageScope())) {
                    throw ExceptionResultEnum.ERROR.exception("通用规则中卷袋贴字段未配置");
                }
                JSONObject packageObject = JSONObject.parseObject(basicExamRule.getPackageScope());
                List<CodeNameEnable> packageScopeList = JSONObject.parseArray(packageObject.getString("basic"), CodeNameEnable.class);
                for (CodeNameEnable jsonObject : packageScopeList) {
                    Optional<CodeNameEnable> objectOptional = displayRanges.stream().filter(m -> m.getCode().equals(jsonObject.getCode())).findFirst();
                    if (objectOptional.isPresent()) {
                        jsonObject.setEnable(objectOptional.get().getEnable());
                    } else {
                        jsonObject.setEnable(false);
                    }
                }
                // 单独处理试卷数量、应考人数、实考人数
                List<CodeName> skipCodes = Arrays.asList(new CodeName("paperCount", "试卷数量"), new CodeName("examCount", "应考人数"), new CodeName("actualExamCount", "实考人数"));
                for (CodeName skipCode : skipCodes) {
                    Optional<CodeNameEnable> objectOptional = displayRanges.stream().filter(m -> m.getCode().equals(skipCode.getCode())).findFirst();
                    if (objectOptional.isPresent()) {
                        packageScopeList.add(objectOptional.get());
                    } else {
                        packageScopeList.add(new CodeNameEnable(skipCode.getCode(), skipCode.getName(), false));
                    }
                }
                for (CodeNameEnable displayRange : displayRanges) {
                    if (skipCodes.contains(displayRange.getCode())) {

                    }
                }
                object.put("basic", packageScopeList);
                basicTemplate.setDisplayRange(JSONObject.toJSONString(object));
            }
        }
        return basicTemplate;
    }

    /**
     * 查找模版(机构同级及以下)
     *
     * @param ids
     * @return
     */
    @Override
    public List<TemplatePrintInfoResult> findTemplateInfoByOrgIds(List<Long> ids) {
        return basicTemplateMapper.findTemplateInfoByOrgIds(ids);
    }

    @Override
    public String preview(Long id) {
        BasicTemplate basicTemplate = basicTemplateMapper.selectById(id);
        String classifyStr = basicTemplate.getClassify().name();
        List<String> stringList = ClassifyEnum.listTypes().stream().map(EnumResult::getCode).collect(Collectors.toList());
        if (!stringList.contains(classifyStr)) {
            throw ExceptionResultEnum.ERROR.exception("模板类型有误");
        }
        ClassifyEnum classifyEnum = ClassifyEnum.valueOf(classifyStr);

        File file = null;
        try {
            file = SystemConstant.getFileTempVar(SystemConstant.PDF_PREFIX);
            String destUrl = file.getPath();
            // 签到表
            if (ClassifyEnum.SIGN.equals(classifyEnum)) {
                if (StringUtils.isBlank(basicTemplate.getPreviewPath())) {
                    File uploadFile = PdfFillUtils.parseSignTempData(basicTemplate, destUrl);
                    if (uploadFile != null) {
                        String fileName = basicTemplate.getId() + SystemConstant.PDF_PREFIX;
                        basicTemplate.setPreviewPath(JSON.toJSONString(fileUploadService.uploadFile(uploadFile, UploadFileEnum.PDF, fileName)));
                        basicTemplateMapper.updateById(basicTemplate);
                    }
                }
                return basicTemplate.getPreviewPath() == null ? null : fileUploadService.filePreview(basicTemplate.getPreviewPath());
            } else if (ClassifyEnum.PACKAGE.equals(classifyEnum)) {
                if (StringUtils.isBlank(basicTemplate.getPreviewPath())) {
                    File uploadFile = PdfFillUtils.packageTempData(basicTemplate.getDisplayRange(), destUrl);
                    if (uploadFile != null) {
                        String fileName = basicTemplate.getId() + SystemConstant.PDF_PREFIX;
                        basicTemplate.setPreviewPath(JSON.toJSONString(fileUploadService.uploadFile(uploadFile, UploadFileEnum.PDF, fileName)));
                        basicTemplateMapper.updateById(basicTemplate);
                    }
                }
                return basicTemplate.getPreviewPath() == null ? null : fileUploadService.filePreview(basicTemplate.getPreviewPath());
            } else if (ClassifyEnum.CHECK_IN.equals(classifyEnum)) {
                BasicAttachment attachment = basicAttachmentService.getById(basicTemplate.getAttachmentId());
                return attachment == null ? null : fileUploadService.filePreview(attachment.getPath());
            } else {
                throw ExceptionResultEnum.ERROR.exception("不支持当前模板预览");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (Objects.nonNull(file)) {
                file.delete();
            }
        }
        return null;
    }

    @Override
    public boolean remove(Long id) {
        BasicTemplate basicTemplate = this.getById(id);
        // 考试关联印品
        Long schoolId = Long.valueOf(ServletUtil.getRequestHeaderSchoolId().toString());
        List<BasicPrintConfig> basicPrintConfigList = basicPrintConfigService.listBySchoolId(schoolId);
        if (!basicPrintConfigList.isEmpty()) {
            List<JSONObject> objects = new ArrayList<>();
            for (BasicPrintConfig basicPrintConfig : basicPrintConfigList) {
                if (ClassifyEnum.SIGN.equals(basicTemplate.getClassify()) || ClassifyEnum.PACKAGE.equals(basicTemplate.getClassify())) {
                    objects = JSON.parseArray(basicPrintConfig.getVariableContent(), JSONObject.class);
                } else if (ClassifyEnum.CHECK_IN.equals(basicTemplate.getClassify())) {
                    objects = JSON.parseArray(basicPrintConfig.getOrdinaryContent(), JSONObject.class);
                }
                List<JSONObject> jsonObjects = objects.stream().filter(m -> m.getString("type").equals(basicTemplate.getClassify().name()) && m.getLong("templateId").equals(id)).collect(Collectors.toList());
                if (!jsonObjects.isEmpty()) {
                    throw ExceptionResultEnum.ERROR.exception("模板名称[" + basicTemplate.getName() + "]的" + basicTemplate.getClassify().getName() + "已使用，不能删除");
                }
            }
        }
        return this.removeById(id);
    }
}
