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

import com.qqchen.deploy.backend.framework.annotation.ServiceType;
import com.qqchen.deploy.backend.framework.enums.ResponseCode;
import com.qqchen.deploy.backend.framework.exception.BusinessException;
import com.qqchen.deploy.backend.framework.exception.UniqueConstraintException;
import com.qqchen.deploy.backend.framework.service.impl.BaseServiceImpl;
import com.qqchen.deploy.backend.framework.utils.JsonUtils;
import com.qqchen.deploy.backend.notification.adapter.INotificationChannelAdapter;
import com.qqchen.deploy.backend.notification.converter.NotificationChannelConverter;
import com.qqchen.deploy.backend.notification.entity.config.BaseNotificationConfig;
import com.qqchen.deploy.backend.notification.entity.config.EmailNotificationConfig;
import com.qqchen.deploy.backend.notification.dto.NotificationChannelDTO;
import com.qqchen.deploy.backend.notification.dto.NotificationChannelQuery;
import com.qqchen.deploy.backend.notification.dto.BaseSendNotificationRequest;
import com.qqchen.deploy.backend.notification.entity.config.WeworkNotificationConfig;
import com.qqchen.deploy.backend.notification.entity.NotificationChannel;
import com.qqchen.deploy.backend.notification.factory.NotificationChannelAdapterFactory;
import com.qqchen.deploy.backend.notification.repository.INotificationChannelRepository;
import com.qqchen.deploy.backend.notification.service.INotificationChannelService;
import com.qqchen.deploy.backend.notification.service.INotificationSendService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import static com.qqchen.deploy.backend.framework.annotation.ServiceType.Type.DATABASE;

/**
 * 通知渠道Service实现
 *
 * @author qqchen
 * @since 2025-10-22
 */
@Slf4j
@Service
@ServiceType(DATABASE)
public class NotificationChannelServiceImpl extends BaseServiceImpl<NotificationChannel, NotificationChannelDTO, NotificationChannelQuery, Long> implements INotificationChannelService {

    @Resource
    private INotificationChannelRepository notificationChannelRepository;

    @Resource
    private INotificationSendService notificationSendService;

    @Resource
    private NotificationChannelAdapterFactory adapterFactory;

    @Override
    protected void validateUniqueConstraints(NotificationChannelDTO dto) {
        // 检查渠道名称唯一性
        if (notificationChannelRepository.existsByNameAndDeletedFalse(dto.getName())) {
            throw new UniqueConstraintException(ResponseCode.CONFLICT, "name", dto.getName());
        }
    }

    @Override
    @Transactional
    public boolean testConnection(Long id) {
        // 1. 查询渠道配置
        NotificationChannel channel = notificationChannelRepository.findById(id)
            .orElseThrow(() -> new BusinessException(ResponseCode.DATA_NOT_FOUND));

        log.info("开始测试通知渠道: id={}, name={}, type={}",
            id, channel.getName(), channel.getChannelType());

        // 2. 创建测试消息
        BaseSendNotificationRequest testRequest = createTestRequest(channel);

        // 3. 发送测试消息（复用 send 逻辑，测试完整的发送流程）
        try {
            notificationSendService.send(channel, testRequest);
            log.info("通知渠道测试成功: id={}, name={}", id, channel.getName());
            return true;
        } catch (Exception e) {
            log.error("通知渠道测试失败: id={}, name={}, 错误: {}",
                id, channel.getName(), e.getMessage(), e);
            throw new BusinessException(ResponseCode.ERROR, new Object[] {"测试失败: " + e.getMessage()});
        }
    }

    /**
     * 创建测试消息
     */
    private BaseSendNotificationRequest createTestRequest(NotificationChannel channel) {
        String testContent = String.format(
            "【通知渠道测试】\n" +
            "渠道名称：%s\n" +
            "渠道类型：%s\n" +
            "测试时间：%s\n\n" +
            "如果您收到此消息，说明通知渠道配置正确！",
            channel.getName(),
            channel.getChannelType().getDescription(),
            java.time.LocalDateTime.now().format(java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))
        );
        
        switch (channel.getChannelType()) {
            case WEWORK -> {
                com.qqchen.deploy.backend.notification.dto.WeworkSendNotificationRequest request = 
                    new com.qqchen.deploy.backend.notification.dto.WeworkSendNotificationRequest();
                request.setContent(testContent);
                request.setTitle("【测试消息】通知渠道连接测试");
                request.setMessageType(com.qqchen.deploy.backend.notification.enums.WeworkMessageTypeEnum.TEXT);
                return request;
            }
            case EMAIL -> {
                com.qqchen.deploy.backend.notification.dto.EmailSendNotificationRequest request = 
                    new com.qqchen.deploy.backend.notification.dto.EmailSendNotificationRequest();
                request.setContent(testContent);
                request.setTitle("【测试消息】通知渠道连接测试");
                request.setToReceivers(java.util.Arrays.asList("admin@company.com"));
                return request;
            }
            default -> throw new BusinessException(ResponseCode.ERROR, 
                new Object[]{"不支持的渠道类型: " + channel.getChannelType()});
        }
    }

    @Override
    @Transactional
    public void enable(Long id) {
        NotificationChannel channel = notificationChannelRepository.findById(id)
            .orElseThrow(() -> new BusinessException(ResponseCode.DATA_NOT_FOUND));

        channel.setEnabled(true);
        notificationChannelRepository.save(channel);

        log.info("启用通知渠道: id={}, name={}", id, channel.getName());
    }

    @Override
    @Transactional
    public void disable(Long id) {
        NotificationChannel channel = notificationChannelRepository.findById(id)
            .orElseThrow(() -> new BusinessException(ResponseCode.DATA_NOT_FOUND));

        channel.setEnabled(false);
        notificationChannelRepository.save(channel);

        log.info("禁用通知渠道: id={}, name={}", id, channel.getName());
    }


    /**
     * 将Map配置转换为具体的配置类型
     */
    private BaseNotificationConfig convertConfig(NotificationChannel channel) {
        return switch (channel.getChannelType()) {
            case WEWORK -> JsonUtils.fromMap(channel.getConfig(), WeworkNotificationConfig.class);
            case EMAIL -> JsonUtils.fromMap(channel.getConfig(), EmailNotificationConfig.class);
            default -> throw new IllegalArgumentException("不支持的渠道类型: " + channel.getChannelType());
        };
    }
}

