package com.weather.modules.sys.alert;

import com.weather.modules.sys.vo.SysAlertVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.stream.Collectors;

/**
 * SSE 连接管理服务。
 * 管理所有活跃的 SSE 连接，监听 {@link AlertCreatedEvent} 并实时推送给前端。
 */
@Slf4j
@Service
public class SseAlertService {

    private final Set<SseEmitter> emitters = new CopyOnWriteArraySet<>();

    /** SSE 连接超时时间（30分钟），避免客户端异常断开后连接泄漏 */
    private static final long SSE_TIMEOUT_MS = 30 * 60 * 1000L;

    /**
     * 创建并注册一个新的 SSE 连接。
     * 绑定清理回调：连接完成/超时/异常时自动移除。
     */
    public SseEmitter createEmitter() {
        SseEmitter emitter = new SseEmitter(SSE_TIMEOUT_MS);
        emitters.add(emitter);
        log.info("SSE 连接已建立，当前连接数: {}", emitters.size());

        emitter.onCompletion(() -> {
            emitters.remove(emitter);
            log.info("SSE 连接已关闭(completion)，当前连接数: {}", emitters.size());
        });
        emitter.onTimeout(() -> {
            emitters.remove(emitter);
            log.info("SSE 连接已关闭(timeout)，当前连接数: {}", emitters.size());
        });
        emitter.onError(e -> {
            emitters.remove(emitter);
            log.info("SSE 连接已关闭(error)，当前连接数: {}", emitters.size());
        });

        // 初始连接确认事件
        try {
            emitter.send(SseEmitter.event().name("connected").data("ok"));
        } catch (IOException e) {
            emitters.remove(emitter);
        }

        return emitter;
    }

    /**
     * 监听通知创建事件，广播到所有活跃 SSE 连接。
     */
    @EventListener
    public void onAlertCreated(AlertCreatedEvent event) {
        SysAlertVO alert = event.getAlert();
        if (emitters.isEmpty()) {
            return;
        }
        log.info("广播新通知 [{}] 到 {} 个 SSE 连接", alert.getTitle(), emitters.size());
        for (SseEmitter emitter : emitters) {
            try {
                emitter.send(SseEmitter.event().name("alert").data(alert));
            } catch (IOException e) {
                emitters.remove(emitter);
                log.debug("SSE 发送失败，移除连接");
            }
        }
    }

    /**
     * 监听通知撤回事件，广播到所有活跃 SSE 连接。
     */
    @EventListener
    public void onAlertWithdrawn(AlertWithdrawnEvent event) {
        if (emitters.isEmpty()) return;
        Map<String, String> data = Map.of("id", String.valueOf(event.getAlertId()));
        log.info("广播撤回通知 [{}] 到 {} 个 SSE 连接", event.getAlertId(), emitters.size());
        for (SseEmitter emitter : emitters) {
            try {
                emitter.send(SseEmitter.event().name("alert-withdrawn").data(data));
            } catch (IOException e) {
                emitters.remove(emitter);
            }
        }
    }

    /**
     * 监听通知删除事件，广播到所有活跃 SSE 连接。
     */
    @EventListener
    public void onAlertDeleted(AlertDeletedEvent event) {
        if (emitters.isEmpty()) return;
        List<String> ids = Arrays.stream(event.getAlertIds())
                .map(String::valueOf)
                .collect(Collectors.toList());
        Map<String, List<String>> data = Map.of("ids", ids);
        log.info("广播删除通知 {} 条到 {} 个 SSE 连接", ids.size(), emitters.size());
        for (SseEmitter emitter : emitters) {
            try {
                emitter.send(SseEmitter.event().name("alert-deleted").data(data));
            } catch (IOException e) {
                emitters.remove(emitter);
            }
        }
    }

    /**
     * 当前活跃连接数。
     */
    public int getActiveCount() {
        return emitters.size();
    }
}
