package gc.mda.kcg.collector.sensor;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import gc.mda.kcg.collector.CollectorStatusTracker;
import gc.mda.kcg.domain.sensor.PressureReading;
import gc.mda.kcg.domain.sensor.PressureReadingRepository;
import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import java.time.Instant;
import java.time.OffsetDateTime;
import java.time.format.DateTimeParseException;

@Slf4j
@Component
@RequiredArgsConstructor
public class PressureCollector {

    private static final String[] STATION_NAMES = {"tehran", "isfahan", "bandar-abbas", "shiraz", "tabriz"};
    private static final double[] LATS = {35.69, 32.65, 27.19, 29.59, 38.08};
    private static final double[] LNGS = {51.39, 51.68, 56.27, 52.58, 46.29};

    private static final String OPEN_METEO_URL =
        "https://api.open-meteo.com/v1/forecast?" +
        "latitude=35.69,32.65,27.19,29.59,38.08" +
        "&longitude=51.39,51.68,56.27,52.58,46.29" +
        "&hourly=surface_pressure&past_hours=24&forecast_hours=0&timezone=UTC";

    private final RestTemplate restTemplate;
    private final ObjectMapper objectMapper;
    private final PressureReadingRepository repository;
    private final CollectorStatusTracker tracker;

    @PostConstruct
    public void init() {
        Thread.ofVirtual().name("pressure-init").start(() -> {
            log.info("Open-Meteo 기압 데이터 초기 로드");
            collect();
        });
    }

    @Scheduled(initialDelay = 45_000, fixedDelay = 600_000)
    public void collectScheduled() {
        collect();
    }

    private void collect() {
        try {
            String body = restTemplate.getForObject(OPEN_METEO_URL, String.class);
            if (body == null || body.isBlank()) return;

            JsonNode root = objectMapper.readTree(body);
            int saved = 0;
            Instant now = Instant.now();

            // Open-Meteo 멀티 위치: 배열 형태 응답
            if (root.isArray()) {
                for (int i = 0; i < root.size() && i < STATION_NAMES.length; i++) {
                    saved += parseStation(root.get(i), STATION_NAMES[i], LATS[i], LNGS[i], now);
                }
            } else {
                // 단일 위치 응답 (파라미터 1개일 때)
                saved += parseStation(root, STATION_NAMES[0], LATS[0], LNGS[0], now);
            }

            tracker.recordSuccess("pressure", "iran", saved);
            log.debug("Open-Meteo 기압 수집 완료: {}건 저장", saved);
        } catch (Exception e) {
            tracker.recordFailure("pressure", "iran", e.getMessage());
            log.warn("Open-Meteo 기압 수집 실패: {}", e.getMessage());
        }
    }

    private int parseStation(JsonNode stationData, String station, double lat, double lng, Instant now) {
        JsonNode hourly = stationData.path("hourly");
        JsonNode times = hourly.path("time");
        JsonNode pressures = hourly.path("surface_pressure");
        if (!times.isArray() || !pressures.isArray()) return 0;

        int saved = 0;
        for (int j = 0; j < times.size() && j < pressures.size(); j++) {
            String timeStr = times.get(j).asText();
            double pressure = pressures.get(j).asDouble(Double.NaN);
            if (Double.isNaN(pressure)) continue;

            try {
                // Open-Meteo 시간 형식: "2026-03-18T07:00" (Z 없음) → Z 추가
                Instant readingTime = OffsetDateTime.parse(timeStr + "Z").toInstant();
                if (repository.existsByStationAndReadingTime(station, readingTime)) continue;
                repository.save(PressureReading.builder()
                        .station(station)
                        .lat(lat)
                        .lng(lng)
                        .pressureHpa(pressure)
                        .readingTime(readingTime)
                        .collectedAt(now)
                        .build());
                saved++;
            } catch (DateTimeParseException e) {
                log.debug("기압 시간 파싱 실패: {}", timeStr);
            }
        }
        return saved;
    }
}
