package gc.mda.kcg.collector.aircraft;

import gc.mda.kcg.config.CacheConfig;
import gc.mda.kcg.domain.aircraft.AircraftDto;
import lombok.RequiredArgsConstructor;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 항공기 데이터 캐시.
 * 소스별 원본을 유지하고, 병합된 최종 결과를 Caffeine 캐시로 제공.
 */
@Component
@RequiredArgsConstructor
public class AircraftCacheStore {

    private final CacheManager cacheManager;

    // 소스별 원본 버퍼 (region → source → aircraft list) — 병합 전 임시 저장
    private final Map<String, Map<String, List<AircraftDto>>> sourceBuffers = new ConcurrentHashMap<>();
    private final Map<String, Long> lastUpdated = new ConcurrentHashMap<>();

    public static final String SOURCE_LIVE = "live";
    public static final String SOURCE_MIL = "mil";
    public static final String SOURCE_OPENSKY = "opensky";

    public void updateSource(String region, String source, List<AircraftDto> aircraft) {
        sourceBuffers
                .computeIfAbsent(region, k -> new ConcurrentHashMap<>())
                .put(source, Collections.unmodifiableList(new ArrayList<>(aircraft)));
    }

    /**
     * 소스별 데이터를 병합하여 Caffeine 캐시를 갱신.
     * 병합 우선순위: live > mil > opensky (icao24 기준 중복제거)
     */
    public void mergeAndUpdate(String region) {
        Map<String, List<AircraftDto>> sources = sourceBuffers.getOrDefault(region, Map.of());

        List<AircraftDto> fromLive = sources.getOrDefault(SOURCE_LIVE, List.of());
        List<AircraftDto> fromMil = sources.getOrDefault(SOURCE_MIL, List.of());
        List<AircraftDto> fromOpenSky = sources.getOrDefault(SOURCE_OPENSKY, List.of());

        Map<String, AircraftDto> merged = new LinkedHashMap<>();

        for (AircraftDto a : fromLive) {
            merged.put(a.getIcao24(), a);
        }

        for (AircraftDto m : fromMil) {
            AircraftDto existing = merged.get(m.getIcao24());
            if (existing != null) {
                merged.put(m.getIcao24(), AircraftDto.builder()
                        .icao24(existing.getIcao24())
                        .callsign(existing.getCallsign())
                        .lat(existing.getLat())
                        .lng(existing.getLng())
                        .altitude(existing.getAltitude())
                        .velocity(existing.getVelocity())
                        .heading(existing.getHeading())
                        .verticalRate(existing.getVerticalRate())
                        .onGround(existing.isOnGround())
                        .category(m.getCategory())
                        .typecode(m.getTypecode() != null ? m.getTypecode() : existing.getTypecode())
                        .typeDesc(existing.getTypeDesc())
                        .registration(existing.getRegistration())
                        .operator(existing.getOperator())
                        .squawk(existing.getSquawk())
                        .lastSeen(existing.getLastSeen())
                        .build());
            } else {
                merged.put(m.getIcao24(), m);
            }
        }

        for (AircraftDto a : fromOpenSky) {
            merged.putIfAbsent(a.getIcao24(), a);
        }

        List<AircraftDto> result = Collections.unmodifiableList(new ArrayList<>(merged.values()));
        String cacheName = "iran".equals(region) ? CacheConfig.AIRCRAFT_IRAN : CacheConfig.AIRCRAFT_KOREA;
        Cache cache = cacheManager.getCache(cacheName);
        if (cache != null) {
            cache.put("data", result);
        }
        lastUpdated.put(region, System.currentTimeMillis());
    }

    @SuppressWarnings("unchecked")
    public List<AircraftDto> get(String region) {
        String cacheName = "iran".equals(region) ? CacheConfig.AIRCRAFT_IRAN : CacheConfig.AIRCRAFT_KOREA;
        Cache cache = cacheManager.getCache(cacheName);
        if (cache != null) {
            Cache.ValueWrapper wrapper = cache.get("data");
            if (wrapper != null) {
                return (List<AircraftDto>) wrapper.get();
            }
        }
        return List.of();
    }

    public long getLastUpdated(String region) {
        return lastUpdated.getOrDefault(region, 0L);
    }
}
