package com.kt.ai.circuitbreaker;

import com.kt.ai.exception.CircuitBreakerOpenException;
import io.github.resilience4j.circuitbreaker.CircuitBreaker;
import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.function.Supplier;

/**
 * Circuit Breaker Manager
 * - Claude API / GPT-4 API 호출 시 Circuit Breaker 적용
 * - Fallback 처리
 *
 * @author AI Service Team
 * @since 1.0.0
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class CircuitBreakerManager {

    private final CircuitBreakerRegistry circuitBreakerRegistry;

    /**
     * Circuit Breaker를 통한 API 호출
     *
     * @param circuitBreakerName Circuit Breaker 이름 (claudeApi, gpt4Api)
     * @param supplier API 호출 로직
     * @param fallback Fallback 로직
     * @return API 호출 결과 또는 Fallback 결과
     */
    public <T> T executeWithCircuitBreaker(
            String circuitBreakerName,
            Supplier<T> supplier,
            Supplier<T> fallback
    ) {
        CircuitBreaker circuitBreaker = circuitBreakerRegistry.circuitBreaker(circuitBreakerName);

        try {
            // Circuit Breaker 상태 확인
            if (circuitBreaker.getState() == CircuitBreaker.State.OPEN) {
                log.warn("Circuit Breaker is OPEN: {}", circuitBreakerName);
                throw new CircuitBreakerOpenException(circuitBreakerName);
            }

            // Circuit Breaker를 통한 API 호출
            return circuitBreaker.executeSupplier(() -> {
                log.debug("Executing with Circuit Breaker: {}", circuitBreakerName);
                return supplier.get();
            });

        } catch (CircuitBreakerOpenException e) {
            // Circuit Breaker가 열린 경우 Fallback 실행
            log.warn("Circuit Breaker OPEN, executing fallback: {}", circuitBreakerName);
            if (fallback != null) {
                return fallback.get();
            }
            throw e;

        } catch (Exception e) {
            // 기타 예외 발생 시 Fallback 실행
            log.error("API call failed, executing fallback: {}", circuitBreakerName, e);
            if (fallback != null) {
                return fallback.get();
            }
            throw e;
        }
    }

    /**
     * Circuit Breaker를 통한 API 호출 (Fallback 없음)
     */
    public <T> T executeWithCircuitBreaker(String circuitBreakerName, Supplier<T> supplier) {
        return executeWithCircuitBreaker(circuitBreakerName, supplier, null);
    }

    /**
     * Circuit Breaker 상태 조회
     */
    public CircuitBreaker.State getCircuitBreakerState(String circuitBreakerName) {
        CircuitBreaker circuitBreaker = circuitBreakerRegistry.circuitBreaker(circuitBreakerName);
        return circuitBreaker.getState();
    }
}
