package com.qqchen.deploy.backend.notification.service.impl;

import com.qqchen.deploy.backend.framework.exception.BusinessException;
import com.qqchen.deploy.backend.framework.enums.ResponseCode;
import com.qqchen.deploy.backend.framework.service.impl.BaseServiceImpl;
import com.qqchen.deploy.backend.framework.utils.JsonUtils;
import com.qqchen.deploy.backend.notification.converter.NotificationTemplateConverter;
import com.qqchen.deploy.backend.notification.dto.EmailSendNotificationRequest;
import com.qqchen.deploy.backend.notification.dto.NotificationTemplateDTO;
import com.qqchen.deploy.backend.notification.dto.WeworkSendNotificationRequest;
import com.qqchen.deploy.backend.notification.dto.template.NotificationTemplateQuery;
import com.qqchen.deploy.backend.notification.entity.NotificationTemplate;
import com.qqchen.deploy.backend.notification.entity.config.BaseTemplateConfig;
import com.qqchen.deploy.backend.notification.entity.config.EmailTemplateConfig;
import com.qqchen.deploy.backend.notification.entity.config.WeworkTemplateConfig;
import com.qqchen.deploy.backend.notification.enums.NotificationChannelTypeEnum;
import com.qqchen.deploy.backend.notification.enums.WeworkMessageTypeEnum;
import com.qqchen.deploy.backend.notification.repository.INotificationTemplateRepository;
import com.qqchen.deploy.backend.notification.service.INotificationSendService;
import com.qqchen.deploy.backend.notification.service.INotificationTemplateService;
import freemarker.template.Configuration;
import freemarker.template.Template;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.StringReader;
import java.io.StringWriter;
import java.util.List;
import java.util.Map;

/**
 * 通知模板Service实现类
 *
 * @author qqchen
 * @since 2025-11-12
 */
@Slf4j
@Service
public class NotificationTemplateServiceImpl extends BaseServiceImpl<NotificationTemplate, NotificationTemplateDTO, NotificationTemplateQuery, Long> implements INotificationTemplateService {

    @Resource
    private INotificationTemplateRepository notificationTemplateRepository;

    @Resource
    private NotificationTemplateConverter notificationTemplateConverter;

    @Resource
    private Configuration freemarkerConfig;

    @Override
    protected void validateUniqueConstraints(NotificationTemplateDTO dto) {
        // 检查编码是否重复
        if (existsByCode(dto.getCode(), dto.getId())) {
            throw new BusinessException(ResponseCode.NOTIFICATION_TEMPLATE_CODE_EXISTS);
        }
    }

    @Override
    public String renderTemplate(String templateContext, Map<String, Object> params) {
        return processTemplate(templateContext, params);
    }

    @Override
    public String renderByCode(String templateCode, Map<String, Object> params) {
        NotificationTemplate template = getTemplateByCode(templateCode);
        return processTemplate(template.getContentTemplate(), params);
    }

    @Override
    public String renderById(Long id, Map<String, Object> params) {
        NotificationTemplate template = getTemplateById(id);
        return processTemplate(template.getContentTemplate(), params);
    }

    /**
     * 根据模板ID渲染标题
     */
    public String renderTitleById(Long id, Map<String, Object> params) {
        NotificationTemplate template = getTemplateById(id);
        if (template.getTitleTemplate() == null || template.getTitleTemplate().trim().isEmpty()) {
            return null; // 没有标题模板则返回null
        }
        return processTemplate(template.getTitleTemplate(), params);
    }


    @Override
    public NotificationTemplateDTO getByCode(String code) {
        NotificationTemplate template = getTemplateByCode(code);
        return notificationTemplateConverter.toDto(template);
    }

    @Override
    public boolean existsByCode(String code, Long id) {
        if (id == null) {
            return notificationTemplateRepository.findByCode(code).isPresent();
        }
        return notificationTemplateRepository.existsByCodeAndIdNot(code, id);
    }

    /**
     * 根据编码获取模板实体
     */
    private NotificationTemplate getTemplateByCode(String code) {
        return notificationTemplateRepository.findByCodeAndEnabled(code, true)
            .orElseThrow(() -> new BusinessException(ResponseCode.NOTIFICATION_TEMPLATE_NOT_FOUND));
    }

    private NotificationTemplate getTemplateById(Long id) {
        return notificationTemplateRepository.findByIdAndEnabled(id, true)
            .orElseThrow(() -> new BusinessException(ResponseCode.NOTIFICATION_TEMPLATE_NOT_FOUND));
    }


    /**
     * FreeMarker模板处理
     */
    private String processTemplate(String templateContent, Map<String, Object> params) {
        try {
            Template template = new Template("notification", new StringReader(templateContent), freemarkerConfig);
            StringWriter writer = new StringWriter();
            template.process(params, writer);
            return writer.toString();
        } catch (freemarker.core.InvalidReferenceException e) {
            // 提取缺失的变量名
            String errorMessage = e.getMessage();
            String missingVariable = extractMissingVariable(errorMessage);
            String friendlyMessage = String.format("缺少必需的参数 '%s'，请检查传入的参数是否完整", missingVariable);
            log.error("模板渲染失败: {}", friendlyMessage, e);
            throw new BusinessException(ResponseCode.NOTIFICATION_TEMPLATE_RENDER_ERROR, new Object[]{friendlyMessage});
        } catch (Exception e) {
            String friendlyMessage = "模板渲染失败：" + e.getMessage();
            log.error("模板渲染失败: {}", friendlyMessage, e);
            throw new BusinessException(ResponseCode.NOTIFICATION_TEMPLATE_RENDER_ERROR, new Object[]{friendlyMessage});
        }
    }

    /**
     * 从FreeMarker错误信息中提取缺失的变量名
     */
    private String extractMissingVariable(String errorMessage) {
        // 错误信息格式: "The following has evaluated to null or missing: ==> variableName [in template ...]"
        if (errorMessage != null && errorMessage.contains("==> ")) {
            int start = errorMessage.indexOf("==> ") + 4;
            int end = errorMessage.indexOf(" ", start);
            if (end == -1) {
                end = errorMessage.indexOf("[", start);
            }
            if (end > start) {
                return errorMessage.substring(start, end).trim();
            }
        }
        return "未知参数";
    }

    @Override
    @Transactional
    public void enable(Long id) {
        NotificationTemplate template = notificationTemplateRepository.findById(id)
            .orElseThrow(() -> new BusinessException(ResponseCode.NOTIFICATION_TEMPLATE_NOT_FOUND));
        template.setEnabled(true);
        notificationTemplateRepository.save(template);
    }

    @Override
    @Transactional
    public void disable(Long id) {
        NotificationTemplate template = notificationTemplateRepository.findById(id)
            .orElseThrow(() -> new BusinessException(ResponseCode.NOTIFICATION_TEMPLATE_NOT_FOUND));
        template.setEnabled(false);
        notificationTemplateRepository.save(template);
    }

    /**
     * 将Map配置转换为具体的模板配置类型
     */
    public BaseTemplateConfig convertTemplateConfig(NotificationTemplate template) {
        if (template.getTemplateConfig() == null) {
            return getDefaultTemplateConfig(template.getChannelType());
        }

        return switch (template.getChannelType()) {
            case WEWORK -> JsonUtils.fromMap(template.getTemplateConfig(), WeworkTemplateConfig.class);
            case EMAIL -> JsonUtils.fromMap(template.getTemplateConfig(), EmailTemplateConfig.class);
            default -> throw new IllegalArgumentException("不支持的渠道类型: " + template.getChannelType());
        };
    }

    /**
     * 获取默认模板配置
     */
    private BaseTemplateConfig getDefaultTemplateConfig(NotificationChannelTypeEnum channelType) {
        return switch (channelType) {
            case WEWORK -> new WeworkTemplateConfig();
            case EMAIL -> new EmailTemplateConfig();
            default -> throw new IllegalArgumentException("不支持的渠道类型: " + channelType);
        };
    }
}
