package com.seer.teach.openapi.service.impl;

import com.seer.teach.openapi.cache.OpenApiSseLifeCycleCacheService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Flux;
import reactor.core.publisher.SignalType;

import java.time.Duration;

/**
 * SSE 流式请求服务
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class SseFactoryService {

    private final WebClient webClient;

    private final OpenApiSseLifeCycleCacheService openApiSseLifeCycleCacheService;

    /**
     * 发起 SSE 流式请求并返回 Flux<SseResponse<T>>
     *
     * @param uri          SSE 服务地址
     * @param request      请求体
     * @param method       HTTP 方法
     * @param redisKey     Redis 缓存键前缀
     * @param sn           用户 SN
     * @param sessionId    会话 ID
     * @param timeOut      超时时间（秒）
     * @param responseType 响应类型
     */
    public <T, R> Flux<R> streamSse(
            String uri,
            T request,
            HttpMethod method,
            String redisKey,
            String sn,
            Integer sessionId,
            Integer timeOut,
            Class<R> responseType
    ) {
        String bizName = redisKey.replace(":", "");
        return webClient
                .method(method)
                .uri(uri)
                .contentType(MediaType.APPLICATION_JSON)
                .accept(MediaType.TEXT_EVENT_STREAM)
                .bodyValue(request)
                .retrieve()
                .bodyToFlux(responseType)
                .timeout(Duration.ofSeconds(timeOut))
                .doOnSubscribe(sub -> {
                    openApiSseLifeCycleCacheService.saveSession(redisKey, sn, sessionId);
                    log.info("{} 建立连接, redisKey={}, sn={}, sessionId={}", bizName, redisKey, sn, sessionId);
                })
                .doOnComplete(() -> {
                    openApiSseLifeCycleCacheService.removeSession(redisKey, sn);
                    log.info("{} 结束, redisKey={}, sn={}, sessionId={}", bizName, redisKey, sn, sessionId);
                })
                .doOnError(error -> {
                    openApiSseLifeCycleCacheService.removeSession(redisKey, sn);
                    log.error("{} 出错, redisKey={}, sn={}, error={}, sessionId={}", bizName, redisKey, sn, error, sessionId);
                })
                .doFinally(signal -> {
                    if (signal == SignalType.CANCEL) {
                        openApiSseLifeCycleCacheService.removeSession(redisKey, sn);
                        log.warn("{} 被取消, redisKey={}, sn={}, signal={}, sessionId={}", bizName, redisKey, sn, signal, sessionId);
                    }
                });
    }

    /**
     * 默认 POST 方法的 SSE 流式请求
     */
    public <T, R> Flux<R> streamSse(
            String uri,
            T request,
            String redisKey,
            String sn,
            Integer sessionId,
            Integer timeOut,
            Class<R> responseType
    ) {
        return streamSse(uri, request, HttpMethod.POST, redisKey, sn, sessionId, timeOut, responseType);
    }
}
