package com.eactive.eai.manage.inflow;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.springframework.stereotype.Service;

import com.eactive.eai.common.inflow.AbstractInflowControlManager;
import com.eactive.eai.common.inflow.InflowControlUtil;
import com.eactive.eai.common.inflow.InflowTargetVO;
import com.eactive.eai.common.inflow.dual.DualCustomBucket;
import com.eactive.eai.common.inflow.dual.DualInflowControlManager;

/**
 * 어댑터/인터페이스/클라이언트 버킷 상태 조회 서비스.
 *
 * DualInflowControlManager 가 활성화된 경우에만 동작한다.
 * InflowControlManager 가 기본 구현체인 경우 빈 목록 또는 null 을 반환한다.
 */
@Service
public class InflowTargetBucketService {

    // -------------------------------------------------------------------------
    // 어댑터
    // -------------------------------------------------------------------------

    public TargetBucketStatusDTO getAdapterBucketStatus(String adapterId) {
        DualInflowControlManager manager = getDualManager();
        if (manager == null) return null;
        DualCustomBucket bucket = manager.getAdapterBucket(adapterId);
        if (bucket == null) return null;
        return toDto(adapterId, "ADAPTER", bucket);
    }

    public List<TargetBucketStatusDTO> getAllAdapterBucketStatus() {
        DualInflowControlManager manager = getDualManager();
        if (manager == null) return new ArrayList<>();
        return toDtoList("ADAPTER", manager.getAdapterBucketMap());
    }

    // -------------------------------------------------------------------------
    // 인터페이스
    // -------------------------------------------------------------------------

    public TargetBucketStatusDTO getInterfaceBucketStatus(String interfaceId) {
        DualInflowControlManager manager = getDualManager();
        if (manager == null) return null;
        DualCustomBucket bucket = manager.getInterfaceBucket(interfaceId);
        if (bucket == null) return null;
        return toDto(interfaceId, "INTERFACE", bucket);
    }

    public List<TargetBucketStatusDTO> getAllInterfaceBucketStatus() {
        DualInflowControlManager manager = getDualManager();
        if (manager == null) return new ArrayList<>();
        return toDtoList("INTERFACE", manager.getInterfaceBucketMap());
    }

    // -------------------------------------------------------------------------
    // Private helpers
    // -------------------------------------------------------------------------

    protected DualInflowControlManager getDualManager() {
        AbstractInflowControlManager base = InflowControlUtil.getInflowControlManager();
        return (base instanceof DualInflowControlManager) ? (DualInflowControlManager) base : null;
    }

    private TargetBucketStatusDTO toDto(String targetId, String targetType, DualCustomBucket bucket) {
        InflowTargetVO vo = bucket.getInflowTargetVo();
        List<GroupBucketStatusDTO.BucketInfo> buckets = new ArrayList<>();

        if (vo.getThresholdPerSecond() > 0) {
            long capacity  = vo.getThresholdPerSecond();
            long available = bucket.getPerSecondAvailableTokens();
            if (available < 0) available = capacity;
            buckets.add(new GroupBucketStatusDTO.BucketInfo(
                    "perSecond", capacity, Math.min(available, capacity), "SEC"));
        }

        if (vo.getThreshold() > 0) {
            long capacity  = vo.getThreshold();
            long available = bucket.getThresholdAvailableTokens();
            if (available < 0) available = capacity;
            buckets.add(new GroupBucketStatusDTO.BucketInfo(
                    "threshold", capacity, Math.min(available, capacity), vo.getThresholdTimeUnit()));
        }

        TargetBucketStatusDTO dto = new TargetBucketStatusDTO();
        dto.setTargetId(targetId);
        dto.setTargetType(targetType);
        dto.setActivate(vo.isActivate());
        dto.setBuckets(buckets);
        return dto;
    }

    private List<TargetBucketStatusDTO> toDtoList(String targetType, Map<String, DualCustomBucket> bucketMap) {
        List<TargetBucketStatusDTO> result = new ArrayList<>();
        for (Map.Entry<String, DualCustomBucket> entry : bucketMap.entrySet()) {
            result.add(toDto(entry.getKey(), targetType, entry.getValue()));
        }
        return result;
    }
}
