import { useState, useEffect } from 'react' import { getRecentObservation, OBS_STATION_CODES, } from '../services/khoaApi' interface WeatherStation { id: string name: string location: { lat: number; lon: number } } export interface EnrichedWeatherStation extends WeatherStation { wind: { speed: number direction: number speed_1k: number speed_3k: number } wave: { height: number period: number } temperature: { current: number feelsLike: number } pressure: number visibility: number } /** * 기상 데이터 가져오기 훅 (KHOA 조위관측소 API 사용) */ export function useWeatherData(stations: WeatherStation[]) { const [weatherStations, setWeatherStations] = useState([]) const [loading, setLoading] = useState(true) const [error, setError] = useState(null) const [lastUpdate, setLastUpdate] = useState(null) useEffect(() => { let isMounted = true // 관측소별 fallback 데이터 생성 function generateFallbackStation(station: WeatherStation): EnrichedWeatherStation { const seed = station.location.lat * 100 + station.location.lon const r = (n: number) => Math.round(n * 10) / 10 // 소수 첫째자리 const windSpeed = r(6 + (seed % 7)) const waveHeight = r(0.8 + (seed % 20) / 10) const temp = r(5 + (seed % 8)) const windDir = [0, 45, 90, 135, 180, 225, 270, 315][Math.floor(seed) % 8] return { ...station, wind: { speed: windSpeed, direction: windDir, speed_1k: r(windSpeed * 0.8), speed_3k: r(windSpeed * 1.2) }, wave: { height: waveHeight, period: 4 + (Math.floor(seed) % 3) }, temperature: { current: temp, feelsLike: r(temp - windSpeed * 0.3) }, pressure: 1010 + (Math.floor(seed) % 12), visibility: 12 + (Math.floor(seed) % 10) } } async function fetchWeatherData() { try { setLoading(true) setError(null) const enrichedStations: EnrichedWeatherStation[] = [] let apiFailed = false for (const station of stations) { if (apiFailed) { enrichedStations.push(generateFallbackStation(station)) continue } try { const obsCode = OBS_STATION_CODES[station.id] if (!obsCode) { enrichedStations.push(generateFallbackStation(station)) continue } const obs = await getRecentObservation(obsCode) if (obs) { const r = (n: number) => Math.round(n * 10) / 10 const windSpeed = r(obs.wind_speed ?? 8.5) const windDir = obs.wind_dir ?? 315 const waterTemp = r(obs.water_temp ?? 8.0) const airPres = Math.round(obs.air_pres ?? 1016) enrichedStations.push({ ...station, wind: { speed: windSpeed, direction: windDir, speed_1k: r(windSpeed * 0.8), speed_3k: r(windSpeed * 1.2) }, wave: { height: r(1.0 + windSpeed * 0.1), period: Math.floor(4 + windSpeed * 0.3) }, temperature: { current: waterTemp, feelsLike: r((obs.air_temp ?? waterTemp) - windSpeed * 0.3) }, pressure: airPres, visibility: airPres > 1010 ? 15 + Math.floor(Math.random() * 5) : 10 }) } else { enrichedStations.push(generateFallbackStation(station)) } await new Promise(resolve => setTimeout(resolve, 100)) } catch (stationError) { if (!apiFailed) { console.warn('KHOA API 연결 실패, fallback 데이터를 사용합니다:', stationError) apiFailed = true } enrichedStations.push(generateFallbackStation(station)) } } if (isMounted) { setWeatherStations(enrichedStations) setLastUpdate(new Date()) setLoading(false) if (apiFailed) { setError('KHOA API 연결 실패 — fallback 데이터 사용 중') } } } catch (err) { console.error('기상 데이터 가져오기 오류:', err) if (isMounted) { setError(err instanceof Error ? err.message : '알 수 없는 오류') setLoading(false) } } } fetchWeatherData() // 10분마다 데이터 갱신 const interval = setInterval(fetchWeatherData, 10 * 60 * 1000) return () => { isMounted = false clearInterval(interval) } }, [stations]) return { weatherStations, loading, error, lastUpdate } }