package org.raddatz.familienarchiv.ocr;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

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

@Service
@Slf4j
public class OcrProgressService {

    private static final long SSE_TIMEOUT = 5 * 60 * 1000L;

    private final ConcurrentHashMap<UUID, List<SseEmitter>> emitters = new ConcurrentHashMap<>();

    public SseEmitter register(UUID jobId) {
        SseEmitter emitter = new SseEmitter(SSE_TIMEOUT);
        emitters.computeIfAbsent(jobId, k -> new CopyOnWriteArrayList<>()).add(emitter);

        emitter.onCompletion(() -> removeEmitter(jobId, emitter));
        emitter.onTimeout(() -> removeEmitter(jobId, emitter));
        emitter.onError(e -> removeEmitter(jobId, emitter));

        return emitter;
    }

    public void emit(UUID jobId, String eventType, Object data) {
        List<SseEmitter> jobEmitters = emitters.get(jobId);
        if (jobEmitters == null) return;

        for (SseEmitter emitter : jobEmitters) {
            try {
                emitter.send(SseEmitter.event().name(eventType).data(data));
            } catch (IOException e) {
                log.debug("SSE send failed for job {} — removing emitter", jobId);
                removeEmitter(jobId, emitter);
            }
        }
    }

    public void complete(UUID jobId) {
        List<SseEmitter> jobEmitters = emitters.remove(jobId);
        if (jobEmitters == null) return;

        for (SseEmitter emitter : jobEmitters) {
            try {
                emitter.complete();
            } catch (Exception e) {
                log.debug("SSE complete failed for job {}", jobId);
            }
        }
    }

    private void removeEmitter(UUID jobId, SseEmitter emitter) {
        List<SseEmitter> jobEmitters = emitters.get(jobId);
        if (jobEmitters != null) {
            jobEmitters.remove(emitter);
            if (jobEmitters.isEmpty()) {
                emitters.remove(jobId);
            }
        }
    }
}
