package com.kt.event.content.infra.gateway.client;

import com.azure.storage.blob.BlobClient;
import com.azure.storage.blob.BlobContainerClient;
import com.azure.storage.blob.BlobServiceClient;
import com.azure.storage.blob.BlobServiceClientBuilder;
import com.kt.event.content.biz.usecase.out.CDNUploader;
import io.github.resilience4j.circuitbreaker.CallNotPermittedException;
import io.github.resilience4j.circuitbreaker.CircuitBreaker;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.ByteArrayInputStream;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.UUID;

/**
 * Azure Blob Storage 업로더
 *
 * Azure Blob Storage에 이미지를 업로드하고 CDN URL을 반환
 */
@Slf4j
@Component
public class AzureBlobStorageUploader implements CDNUploader {

    @Value("${azure.storage.connection-string}")
    private String connectionString;

    @Value("${azure.storage.container-name}")
    private String containerName;

    private final CircuitBreaker circuitBreaker;

    private BlobServiceClient blobServiceClient;
    private BlobContainerClient containerClient;

    public AzureBlobStorageUploader(@Qualifier("azureCircuitBreaker") CircuitBreaker circuitBreaker) {
        this.circuitBreaker = circuitBreaker;
    }

    /**
     * Azure Blob Storage 클라이언트 초기화
     */
    @PostConstruct
    public void init() {
        // Connection string이 비어있으면 초기화 건너뛰기
        if (connectionString == null || connectionString.trim().isEmpty()) {
            log.warn("Azure Blob Storage connection string이 설정되지 않았습니다. Azure 업로드 기능을 사용할 수 없습니다.");
            return;
        }

        try {
            log.info("Azure Blob Storage 클라이언트 초기화 시작");

            // BlobServiceClient 생성
            blobServiceClient = new BlobServiceClientBuilder()
                    .connectionString(connectionString)
                    .buildClient();

            // Container 클라이언트 생성 (없으면 생성)
            containerClient = blobServiceClient.getBlobContainerClient(containerName);
            if (!containerClient.exists()) {
                containerClient.create();
                log.info("Azure Blob Container 생성 완료: {}", containerName);
            }

            log.info("Azure Blob Storage 클라이언트 초기화 완료: container={}", containerName);
        } catch (Exception e) {
            log.error("Azure Blob Storage 클라이언트 초기화 실패", e);
            throw new RuntimeException("Azure Blob Storage 초기화 실패: " + e.getMessage(), e);
        }
    }

    /**
     * 이미지 업로드
     *
     * @param imageData 이미지 바이트 데이터
     * @param fileName  파일명 (확장자 포함)
     * @return CDN URL
     */
    @Override
    public String upload(byte[] imageData, String fileName) {
        try {
            // Circuit Breaker로 업로드 메서드 실행
            return circuitBreaker.executeSupplier(() -> doUpload(imageData, fileName));
        } catch (CallNotPermittedException e) {
            log.error("Azure Circuit Breaker가 OPEN 상태입니다. 업로드 차단: fileName={}", fileName);
            throw new RuntimeException("Azure Blob Storage에 일시적으로 접근할 수 없습니다. 잠시 후 다시 시도해주세요.", e);
        } catch (Exception e) {
            log.error("Azure Blob Storage 업로드 실패: fileName={}", fileName, e);
            throw new RuntimeException("이미지 업로드 실패: " + e.getMessage(), e);
        }
    }

    /**
     * 실제 업로드 수행 (Circuit Breaker로 보호됨)
     */
    private String doUpload(byte[] imageData, String fileName) {
        // Container 초기화 확인
        if (containerClient == null) {
            throw new RuntimeException("Azure Blob Storage가 초기화되지 않았습니다. Connection string을 확인해주세요.");
        }

        // 고유한 Blob 이름 생성 (날짜 폴더 구조 + UUID)
        String blobName = generateBlobName(fileName);

        log.info("Azure Blob Storage 업로드 시작: blobName={}, size={} bytes", blobName, imageData.length);

        // BlobClient 생성
        BlobClient blobClient = containerClient.getBlobClient(blobName);

        // 이미지 업로드 (덮어쓰기 허용)
        blobClient.upload(new ByteArrayInputStream(imageData), imageData.length, true);

        // CDN URL 생성
        String cdnUrl = blobClient.getBlobUrl();

        log.info("Azure Blob Storage 업로드 완료: blobName={}, url={}", blobName, cdnUrl);

        return cdnUrl;
    }

    /**
     * Blob 이름 생성
     *
     * 형식: {YYYY}/{MM}/{DD}/{UUID}-{fileName}
     * 예시: 2025/01/27/a1b2c3d4-e5f6-7890-abcd-ef1234567890-event-image.png
     *
     * @param fileName 원본 파일명
     * @return Blob 이름
     */
    private String generateBlobName(String fileName) {
        // 현재 날짜로 폴더 구조 생성
        LocalDateTime now = LocalDateTime.now();
        String dateFolder = now.format(DateTimeFormatter.ofPattern("yyyy/MM/dd"));

        // UUID 생성
        String uuid = UUID.randomUUID().toString();

        // Blob 이름 생성: {날짜폴더}/{UUID}-{파일명}
        return String.format("%s/%s-%s", dateFolder, uuid, fileName);
    }
}
