package com.zt.plat.module.base.service.doctemplate;

import cn.hutool.core.util.StrUtil;
import com.zt.plat.module.base.dal.dataobject.doctemplate.DocTemplateDO;
import com.zt.plat.module.base.dal.dataobject.doctemplate.DocTemplateInstanceDO;
import com.zt.plat.module.base.dal.dao.doctemplate.DocTemplateMapper;
import com.zt.plat.module.base.dal.dao.doctemplate.DocTemplateInstanceMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.springframework.stereotype.Service;

import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import java.io.StringWriter;
import java.util.Map;
import java.util.Properties;

import static com.zt.plat.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.zt.plat.module.base.enums.ErrorCodeConstants.*;

/**
 * 文档模板渲染 Service 实现类
 * 使用 Apache Velocity 模板引擎进行渲染
 *
 * @author 系统生成
 */
@Service
@Slf4j
public class DocTemplateRenderServiceImpl implements DocTemplateRenderService {

    @Resource
    private DocTemplateMapper templateMapper;

    @Resource
    private DocTemplateInstanceMapper instanceMapper;

    /**
     * 初始化 Velocity 引擎
     */
    @PostConstruct
    public void initVelocity() {
        try {
            Properties props = new Properties();
            // 设置编码
            props.setProperty("input.encoding", "UTF-8");
            props.setProperty("output.encoding", "UTF-8");
            // 设置资源加载器为字符串
            props.setProperty("resource.loader", "string");
            props.setProperty("string.resource.loader.class",
                    "org.apache.velocity.runtime.resource.loader.StringResourceLoader");
            // 关闭日志（可选）
            props.setProperty("runtime.log.logsystem.class",
                    "org.apache.velocity.runtime.log.NullLogChute");

            Velocity.init(props);
            log.info("Velocity 模板引擎初始化成功");
        } catch (Exception e) {
            log.error("Velocity 模板引擎初始化失败", e);
            throw new RuntimeException("Velocity 模板引擎初始化失败", e);
        }
    }

    @Override
    public String render(Long templateId, Long instanceId, String content, Map<String, Object> dataMap) {
        // 1. 获取模板内容
        String templateContent = getTemplateContent(templateId, instanceId, content);

        if (StrUtil.isBlank(templateContent)) {
            throw exception(TEMPLATE_NOT_EXISTS);
        }

        // 2. 创建 Velocity 上下文
        VelocityContext context = new VelocityContext();
        if (dataMap != null && !dataMap.isEmpty()) {
            dataMap.forEach(context::put);
        }

        // 3. 渲染模板
        try {
            StringWriter writer = new StringWriter();
            Velocity.evaluate(context, writer, "DocTemplateRender", templateContent);
            String result = writer.toString();

            log.debug("模板渲染成功，数据量: {}, 内容长度: {}",
                    dataMap != null ? dataMap.size() : 0, result.length());

            return result;
        } catch (Exception e) {
            log.error("模板渲染失败，templateId: {}, instanceId: {}", templateId, instanceId, e);
            throw new RuntimeException("模板渲染失败: " + e.getMessage(), e);
        }
    }

    @Override
    public void renderAndSave(Long instanceId, Map<String, Object> dataMap) {
        // 1. 校验实例存在
        DocTemplateInstanceDO instance = instanceMapper.selectById(instanceId);
        if (instance == null) {
            throw exception(TEMPLATE_INSTANCE_NOT_EXISTS);
        }

        // 2. 渲染内容
        String renderedContent = render(null, instanceId, null, dataMap);

        // 3. 更新实例的渲染内容
        DocTemplateInstanceDO updateObj = new DocTemplateInstanceDO();
        updateObj.setId(instanceId);
        updateObj.setRenderedContent(renderedContent);
        instanceMapper.updateById(updateObj);

        log.info("模板实例渲染并保存成功，instanceId: {}", instanceId);
    }

    /**
     * 获取模板内容
     * 优先级：content > instanceId > templateId
     */
    private String getTemplateContent(Long templateId, Long instanceId, String content) {
        // 优先使用直接传入的内容
        if (StrUtil.isNotBlank(content)) {
            return content;
        }

        // 其次使用实例的编辑内容
        if (instanceId != null) {
            DocTemplateInstanceDO instance = instanceMapper.selectById(instanceId);
            if (instance != null && StrUtil.isNotBlank(instance.getEditedContent())) {
                return instance.getEditedContent();
            }
        }

        // 最后使用模板内容
        if (templateId != null) {
            DocTemplateDO template = templateMapper.selectById(templateId);
            if (template != null && StrUtil.isNotBlank(template.getContent())) {
                return template.getContent();
            }
        }

        return null;
    }

}
