package com.kt.event.content.infra.config;

import io.github.resilience4j.circuitbreaker.CircuitBreaker;
import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig;
import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.time.Duration;

/**
 * Resilience4j Circuit Breaker 설정
 *
 * Replicate API 및 Azure Blob Storage에 대한 Circuit Breaker 패턴 적용
 */
@Slf4j
@Configuration
public class Resilience4jConfig {

    /**
     * Replicate API Circuit Breaker
     *
     * - 실패율 50% 이상 시 Open
     * - 최소 5개 요청 후 평가
     * - Open 후 60초 대기 (Half-Open 전환)
     * - Half-Open 상태에서 3개 요청으로 평가
     */
    @Bean
    public CircuitBreaker replicateCircuitBreaker() {
        CircuitBreakerConfig config = CircuitBreakerConfig.custom()
                .failureRateThreshold(50) // 실패율 50% 초과 시 Open
                .slowCallRateThreshold(50) // 느린 호출 50% 초과 시 Open
                .slowCallDurationThreshold(Duration.ofSeconds(120)) // 120초 이상 걸리면 느린 호출로 판단
                .waitDurationInOpenState(Duration.ofSeconds(60)) // Open 후 60초 대기
                .slidingWindowType(CircuitBreakerConfig.SlidingWindowType.COUNT_BASED) // 횟수 기반 평가
                .slidingWindowSize(10) // 최근 10개 요청 평가
                .minimumNumberOfCalls(5) // 최소 5개 요청 후 평가
                .permittedNumberOfCallsInHalfOpenState(3) // Half-Open에서 3개 요청으로 평가
                .automaticTransitionFromOpenToHalfOpenEnabled(true) // 자동 Half-Open 전환
                .build();

        CircuitBreaker circuitBreaker = CircuitBreakerRegistry.of(config).circuitBreaker("replicate");

        // Circuit Breaker 이벤트 로깅
        circuitBreaker.getEventPublisher()
                .onSuccess(event -> log.debug("Replicate Circuit Breaker: Success"))
                .onError(event -> log.warn("Replicate Circuit Breaker: Error - {}", event.getThrowable().getMessage()))
                .onStateTransition(event -> log.warn("Replicate Circuit Breaker: State transition from {} to {}",
                        event.getStateTransition().getFromState(), event.getStateTransition().getToState()))
                .onSlowCallRateExceeded(event -> log.warn("Replicate Circuit Breaker: Slow call rate exceeded"))
                .onFailureRateExceeded(event -> log.warn("Replicate Circuit Breaker: Failure rate exceeded"));

        return circuitBreaker;
    }

    /**
     * Azure Blob Storage Circuit Breaker
     *
     * - 실패율 50% 이상 시 Open
     * - 최소 3개 요청 후 평가
     * - Open 후 30초 대기 (Half-Open 전환)
     * - Half-Open 상태에서 2개 요청으로 평가
     */
    @Bean
    public CircuitBreaker azureCircuitBreaker() {
        CircuitBreakerConfig config = CircuitBreakerConfig.custom()
                .failureRateThreshold(50) // 실패율 50% 초과 시 Open
                .slowCallRateThreshold(50) // 느린 호출 50% 초과 시 Open
                .slowCallDurationThreshold(Duration.ofSeconds(30)) // 30초 이상 걸리면 느린 호출로 판단
                .waitDurationInOpenState(Duration.ofSeconds(30)) // Open 후 30초 대기
                .slidingWindowType(CircuitBreakerConfig.SlidingWindowType.COUNT_BASED) // 횟수 기반 평가
                .slidingWindowSize(10) // 최근 10개 요청 평가
                .minimumNumberOfCalls(3) // 최소 3개 요청 후 평가
                .permittedNumberOfCallsInHalfOpenState(2) // Half-Open에서 2개 요청으로 평가
                .automaticTransitionFromOpenToHalfOpenEnabled(true) // 자동 Half-Open 전환
                .build();

        CircuitBreaker circuitBreaker = CircuitBreakerRegistry.of(config).circuitBreaker("azure");

        // Circuit Breaker 이벤트 로깅
        circuitBreaker.getEventPublisher()
                .onSuccess(event -> log.debug("Azure Circuit Breaker: Success"))
                .onError(event -> log.warn("Azure Circuit Breaker: Error - {}", event.getThrowable().getMessage()))
                .onStateTransition(event -> log.warn("Azure Circuit Breaker: State transition from {} to {}",
                        event.getStateTransition().getFromState(), event.getStateTransition().getToState()))
                .onSlowCallRateExceeded(event -> log.warn("Azure Circuit Breaker: Slow call rate exceeded"))
                .onFailureRateExceeded(event -> log.warn("Azure Circuit Breaker: Failure rate exceeded"));

        return circuitBreaker;
    }
}
