"""
Стратегия Б v2 — исправленный алгоритм поиска fr24_id.

Ключевое исправление:
- Для вылетов SVO: снимок через +20 мин после вылета (самолёт уже в воздухе)
- Для прилётов SVO: снимок за -20 мин до прилёта (самолёт на подходе)
- Расширенный bbox: 200 км вокруг SVO вместо всей МО
- Несколько попыток со сдвигом ±30 мин если первый снимок пустой
"""
import requests, json, time, os
from datetime import datetime, timezone, timedelta
from dotenv import load_dotenv
from noise_model import calc_zone_radii_for_point

load_dotenv(dotenv_path='.env')
KEY  = os.getenv('FLIGHTRADAR24_API_KEY')
BASE = 'https://fr24api.flightradar24.com/api'
H    = {'Authorization': f'Bearer {KEY}', 'Accept': 'application/json', 'Accept-Version': 'v1'}

# Расширенный bbox 200 км вокруг SVO (55.97°N, 37.41°E)
# lat_max, lat_min, lon_min, lon_max
SEARCH_BOUNDS = '57.8,53.8,33.5,41.5'

# bbox для фильтрации точек трека — только МО
MO = {'lat_min': 54.0, 'lat_max': 57.0, 'lon_min': 35.5, 'lon_max': 40.5}
def in_mo(lat, lon):
    return MO['lat_min'] <= lat <= MO['lat_max'] and MO['lon_min'] <= lon <= MO['lon_max']

CACHE_ID  = 'data/cache_SVO_b'   # кэш fr24_id
CACHE_TRK = 'data/cache_SVO'     # кэш треков (общий)
os.makedirs(CACHE_ID, exist_ok=True)
os.makedirs(CACHE_TRK, exist_ok=True)

import sys

# ── Загрузка списка рейсов ───────────────────────────────────────
with open('data/tablo_need_load.json') as f:
    need = json.load(f)

# Дата: из аргумента командной строки или из данных табло
TARGET_DATE = sys.argv[1] if len(sys.argv) > 1 else None
if not TARGET_DATE:
    # Пробуем извлечь из первого рейса
    first = need['flights'][0] if need.get('flights') else {}
    TARGET_DATE = first.get('date') or (first.get('departure') or '')[:10]
if not TARGET_DATE:
    from datetime import date
    TARGET_DATE = str(date.today())
print(f'📅 Дата загрузки: {TARGET_DATE}')

# Дедупликация — у нас дублировались рейсы в табло
seen_fn = set()
flights_todo = []
for fl in need['flights']:
    fn = (fl.get('flight_number') or '').replace(' ','').upper()
    key = fn + fl.get('direction','')
    if key not in seen_fn:
        seen_fn.add(key)
        flights_todo.append(fl)

print(f'📋 Рейсов (после дедупликации): {len(flights_todo)}')
print(f'   (было: {len(need["flights"])})')

# ── Кэш снимков ─────────────────────────────────────────────────
_snapshot_cache = {}  # ts → {callsign: fr24_id}

def get_snapshot(ts):
    if ts in _snapshot_cache:
        return _snapshot_cache[ts]
    r = requests.get(f'{BASE}/historic/flight-positions/full', headers=H,
        params={'bounds': SEARCH_BOUNDS, 'timestamp': ts, 'limit': 500},
        timeout=20)
    if r.status_code == 429:
        print(f'  ⏳ 429, пауза 40с...')
        time.sleep(40)
        r = requests.get(f'{BASE}/historic/flight-positions/full', headers=H,
            params={'bounds': SEARCH_BOUNDS, 'timestamp': ts, 'limit': 500},
            timeout=20)
    result = {}
    if r.ok:
        for item in r.json().get('data', []):
            cs = (item.get('callsign') or '').replace(' ','').upper()
            fn = (item.get('flight') or '').replace(' ','').upper()
            fid = item.get('fr24_id')
            if cs and fid: result[cs] = fid
            if fn and fid: result[fn] = fid
    _snapshot_cache[ts] = result
    return result

def find_fr24_id(flight):
    """Поиск fr24_id: пробуем несколько моментов времени вокруг вылета/прилёта"""
    cs = (flight.get('callsign') or '').replace(' ','').upper()
    fn = (flight.get('flight_number') or '').replace(' ','').upper()
    direction = flight.get('direction', 'departure')

    # Кэш файл
    cache_file = f'{CACHE_ID}/id_{fn}_{direction}.json'
    if os.path.exists(cache_file):
        with open(cache_file) as f:
            return json.load(f).get('fr24_id')

    # Определяем базовое время.
    # Важно: Яндекс.Расписания для прилётов тоже возвращает departure (вылет из др. аэропорта).
    # Поле arrival = null. Поэтому всегда используем departure.
    base_iso = flight.get('departure') or ''
    if not base_iso:
        return None

    try:
        base_dt = datetime.fromisoformat(base_iso.replace('Z','+00:00'))
    except:
        return None

    base_ts = int(base_dt.timestamp())

    # Смещения для поиска:
    # Вылет SVO: +15, +30, +45, +60 мин — самолёт набирает высоту над МО
    # Прилёт в SVO: вылет + 30мин..3ч — самолёт в пути, пробуем поймать над МО
    if direction == 'departure':
        offsets = [15*60, 30*60, 45*60, 60*60]
    else:
        offsets = [60*60, 90*60, 120*60, 150*60, 180*60, 30*60]

    for offset in offsets:
        ts = base_ts + offset
        snapshot = get_snapshot(ts)
        time.sleep(0.8)

        fid = snapshot.get(cs) or snapshot.get(fn)
        if fid:
            with open(cache_file, 'w') as f:
                json.dump({'fr24_id': fid, 'callsign': cs, 'fn': fn}, f)
            return fid

    # Не нашли
    with open(cache_file, 'w') as f:
        json.dump({'fr24_id': None}, f)
    return None

def get_track(fr24_id):
    """Загружаем трек из кэша или API"""
    for cache_dir in [CACHE_TRK, 'data/cache_SVO_offset90m', CACHE_ID]:
        cf = f'{cache_dir}/track_{fr24_id}.json'
        if os.path.exists(cf):
            with open(cf) as f:
                return json.load(f)

    r = requests.get(f'{BASE}/flight-tracks', headers=H,
        params={'flight_id': fr24_id}, timeout=20)
    if r.status_code == 429:
        print(f'  ⏳ 429 (трек), пауза 40с...')
        time.sleep(40)
        r = requests.get(f'{BASE}/flight-tracks', headers=H,
            params={'flight_id': fr24_id}, timeout=20)
    if not r.ok:
        return []
    raw = r.json()
    tracks = raw[0].get('tracks', []) if isinstance(raw, list) and raw else []
    with open(f'{CACHE_TRK}/track_{fr24_id}.json', 'w') as f:
        json.dump(tracks, f)
    return tracks

# ── Основной цикл ────────────────────────────────────────────────
flights_final = []
no_id = 0
no_mo = 0
total = len(flights_todo)

for i, fl in enumerate(flights_todo):
    fn = (fl.get('flight_number') or '').replace(' ','').upper()

    # Поиск fr24_id
    fid = find_fr24_id(fl)

    if not fid:
        no_id += 1
        if (i+1) % 20 == 0:
            print(f'  [{i+1}/{total}] треков: {len(flights_final)}, нет id: {no_id}')
        continue

    # Трек
    tracks = get_track(fid)
    time.sleep(0.8)

    mo_pts = sorted([p for p in tracks if in_mo(p.get('lat',0), p.get('lon',0))],
                    key=lambda p: p.get('timestamp',''))
    if len(mo_pts) < 2:
        no_mo += 1
        continue

    points = []
    for pt in mo_pts:
        alt_ft = pt.get('alt', 0) or 0
        alt_m  = round(alt_ft / 3.28084)
        points.append({
            'lat': pt['lat'], 'lon': pt['lon'],
            'altitude': alt_ft, 'altitude_m': alt_m,
            'speed': pt.get('gspeed', 0), 'heading': pt.get('track', 0),
            'timestamp': pt.get('timestamp', ''),
            'zone_radii': calc_zone_radii_for_point(alt_m),
        })

    flights_final.append({
        'id':            fid,
        'callsign':      fl.get('callsign', fn),
        'flight_number': fl.get('flight_number', ''),
        'aircraft_type': (fl.get('aircraft') or '')[:5],
        'registration':  '',
        'airline':       fl.get('airline', ''),
        'airline_iata':  fl.get('airline_iata', ''),
        'origin':        'SVO' if fl.get('direction') == 'departure' else '',
        'destination':   '' if fl.get('direction') == 'departure' else 'SVO',
        'orig_icao':     'UUEE' if fl.get('direction') == 'departure' else '',
        'dest_icao':     '' if fl.get('direction') == 'departure' else 'UUEE',
        'airport':       'SVO',
        'type':          fl.get('direction', 'departure'),
        'dep_scheduled': fl.get('departure', ''),
        'points':        points,
    })

    if (i+1) % 10 == 0 or i == total-1:
        pts_total = sum(len(f['points']) for f in flights_final)
        print(f'  [{i+1}/{total}] ✅ треков: {len(flights_final)}, точек: {pts_total}, нет id: {no_id}, нет МО: {no_mo}')

# ── Сохраняем ────────────────────────────────────────────────────
print(f'\n✅ Итого: {len(flights_final)} треков над МО')
print(f'   fr24_id не найден: {no_id}')
print(f'   нет точек над МО:  {no_mo}')

out = {
    'airport': 'SVO', 'date': TARGET_DATE,
    'strategy': 'B_v2',
    'flights_count': len(flights_final),
    'flights': flights_final,
}
out_file = f'data/flights_SVO_{TARGET_DATE}_strategy_b.json'
with open(out_file, 'w', encoding='utf-8') as f:
    json.dump(out, f, ensure_ascii=False)

print(f'   Точек: {sum(len(f["points"]) for f in flights_final)}')
print(f'💾 {out_file}')
