package com.yaoai.agent.sse;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;

@Slf4j
@Component
@RequiredArgsConstructor
public class AgentSseManager {

    private final ObjectMapper objectMapper;
    private final Map<Long, List<SseEmitter>> emitters = new ConcurrentHashMap<>();

    public SseEmitter subscribe(Long runId) {
        SseEmitter emitter = new SseEmitter(300_000L);
        List<SseEmitter> list = emitters.computeIfAbsent(runId, k -> new CopyOnWriteArrayList<>());
        list.add(emitter);
        emitter.onCompletion(() -> remove(runId, emitter));
        emitter.onTimeout(() -> remove(runId, emitter));
        emitter.onError(e -> remove(runId, emitter));
        log.debug("SSE subscribed: runId={}, total={}", runId, list.size());
        return emitter;
    }

    public void emit(Long runId, String type, Object data) {
        List<SseEmitter> list = emitters.get(runId);
        if (list == null || list.isEmpty()) return;

        try {
            String json = objectMapper.writeValueAsString(
                    Map.of("type", type, "data", data == null ? Map.of() : data)
            );
            list.removeIf(emitter -> {
                try {
                    emitter.send(SseEmitter.event().name(type).data(json));
                    return false;
                } catch (Exception e) {
                    log.debug("Removed broken SSE emitter for runId={}", runId);
                    return true;
                }
            });
        } catch (Exception e) {
            log.error("SSE emit failed: runId={}, type={}", runId, type, e);
        }
    }

    public void emitLog(Long runId, String level, String message) {
        emit(runId, "log", Map.of("level", level, "message", message,
                "time", java.time.LocalTime.now().toString().substring(0, 8)));
    }

    private void remove(Long runId, SseEmitter emitter) {
        List<SseEmitter> list = emitters.get(runId);
        if (list != null) list.remove(emitter);
    }
}
