package com.example.sse.core;

import org.springframework.stereotype.Component;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;

@Component
public class SseChannelBus {

    // 채널ID -> 구독자 리스트
    private final Map<String, CopyOnWriteArrayList<SseEmitter>> subscribers = new ConcurrentHashMap<>();

    // [수신대기] 패턴이 나오면 해당 채널을 자동 해지
    private static final String END_OF_CALL_MSG = "[수신대기] SM_Wait_Call Result";

    /** 채널 구독 등록 */
    public SseEmitter subscribe(String channelId, Long timeoutMs) {
        SseEmitter emitter = new SseEmitter(timeoutMs);

        //channelId가 없으면 새 리스트를 만들어 넣고, 있으면 기존 리스트를 반환
        subscribers.computeIfAbsent(channelId, k -> new CopyOnWriteArrayList<>()).add(emitter);

        // 완료/타임아웃/에러 시 구독 해제
        emitter.onCompletion(() -> removeEmitter(channelId, emitter));
        emitter.onTimeout(() -> removeEmitter(channelId, emitter));
        emitter.onError(ex -> removeEmitter(channelId, emitter));

        // 연결 직후 더미 메시지
        try {
            emitter.send(SseEmitter.event()
                    .name("connected")
                    .data("subscribed channel=" + channelId));
        } catch (IOException e) {
            emitter.complete();
            removeEmitter(channelId, emitter);
        }

        return emitter;
    }

    /** 로그 라인 publish: 전송 후에 특정 패턴에 따라 자동 해지 */
    public void publish(String channelId, String line) {
        CopyOnWriteArrayList<SseEmitter> list = subscribers.get(channelId);
        if (list == null || list.isEmpty()) {
            System.out.println("SseChannelBus.publish: channelId=" + channelId + ", 채널아이디 찾을수 없음.");
            return;
        }

        for (SseEmitter emitter : list) {
            try {
                emitter.send(SseEmitter.event()
                        .name("channel-log")
                        .data(line)); // data는 문자열 한 줄
                System.out.println("SseChannelBus.publish: send(channelId=" + channelId + ") line=" + line);
            } catch (IOException e) {
                removeEmitter(channelId, emitter);
            }
        }

        if (line != null && line.contains(END_OF_CALL_MSG)) {
            System.out.println("SseChannelBus.publish: matched=" + END_OF_CALL_MSG + ", line=" + line);
            for (SseEmitter emitter : list) {
                removeEmitter(channelId, emitter);
            }
        }
    }

    /** 단일 emitter 제거 유틸 */
    private void removeEmitter(String channelId, SseEmitter emitter) {
        System.out.println("SseChannelBus.removeEmitter: channelId(" +  channelId + ")의 구독을 해지합니다.");
        CopyOnWriteArrayList<SseEmitter> list = subscribers.get(channelId);
        if (list == null) return;
        list.remove(emitter);
        if (list.isEmpty()) {
            subscribers.remove(channelId);
        }
    }

}
