import numpy as np
import time
import warnings

warnings.filterwarnings('ignore')

print("="*100)
print(" IT³ HYPER SCANNER: ULTRA-FAST MATRIX TOPOLOGY AUDIT (m=3 to m=36)")
print(" Режим: Матричный перебор фрактальных сеток вакуума")
print("="*100)

DATA_FILE = "MPCORB_full_cache.dat"

etno_varpi = []
print(f"[*] Загрузка базы {DATA_FILE}...")

try:
    with open(DATA_FILE, 'r', encoding='utf-8', errors='ignore') as f:
        for line in f:
            if len(line) < 100: continue
            parts = line.split()
            if len(parts) >= 12:
                try:
                    a_val = float(parts[10])
                    e_val = float(parts[8])
                    node = float(parts[5])
                    peri = float(parts[6])
                    
                    q_val = a_val * (1.0 - e_val)
                    if a_val > 150.0 and q_val > 30.0:
                        varpi = (node + peri) % 360.0
                        etno_varpi.append(varpi)
                except ValueError:
                    continue

    angles = np.array(etno_varpi)
    print(f"[✓] Изолировано чистых ETNO: {len(angles)}")
    
except FileNotFoundError:
    print(f"[-] Файл не найден!")
    exit()

if len(angles) == 0:
    print("[-] Нет данных.")
    exit()

# Глобальный массив случайного шума для честных бэйзлайнов
# Фиксируем seed, чтобы результаты были повторяемыми
np.random.seed(42)
RAND_ANGLES = np.random.uniform(0, 360, 200000)

# ==============================================================================
# 1. СВЕРХБЫСТРОЕ МАТРИЧНОЕ ЯДРО
# ==============================================================================
def scan_single_m(m, target_angles):
    step = 180.0 / m
    # Сканируем 1000 фаз за один проход матрицы (векторизация)
    phases = np.linspace(0, step, 1000)
    
    # Расстояние от всех орбит до всех узлов при всех фазах
    # diffs shape: (1000 фаз, N орбит)
    diffs = np.abs(target_angles[None, :] - phases[:, None]) % step
    diffs = np.minimum(diffs, step - diffs)
    
    mean_devs = np.mean(diffs, axis=1)
    best_idx = np.argmin(mean_devs)
    
    best_phase = phases[best_idx]
    best_dev = mean_devs[best_idx]
    baseline = step / 4.0
    ratio = best_dev / baseline
    
    return best_phase, best_dev, baseline, ratio

def scan_nested(m1, m2, target_angles):
    step1, step2 = 180.0 / m1, 180.0 / m2
    
    # Грубая сетка для 2D перебора (быстро)
    p1 = np.linspace(0, step1, 50)
    p2 = np.linspace(0, step2, 50)
    
    best_ratio = 999
    best_dev = 999
    
    # Для суперпозиций считаем честный случайный шум один раз (в нулевой фазе)
    # т.к. при смещении сетки мат. ожидание шума не меняется
    nodes1_rand = np.array([i * step1 for i in range(m1 * 2)])
    nodes2_rand = np.array([i * step2 for i in range(m2 * 2)])
    all_nodes_rand = np.concatenate([nodes1_rand, nodes2_rand])
    diffs_r = np.abs(RAND_ANGLES[:, None] - all_nodes_rand)
    diffs_r = np.minimum(diffs_r, 360 - diffs_r)
    baseline = np.mean(np.min(diffs_r, axis=1))

    # Быстрый 2D перебор фаз
    for phase1 in p1:
        nodes1 = np.array([(phase1 + i * step1) % 360 for i in range(m1 * 2)])
        for phase2 in p2:
            nodes2 = np.array([(phase2 + i * step2) % 360 for i in range(m2 * 2)])
            all_nodes = np.concatenate([nodes1, nodes2])
            
            diffs = np.abs(target_angles[:, None] - all_nodes)
            diffs = np.minimum(diffs, 360 - diffs)
            dev = np.mean(np.min(diffs, axis=1))
            
            ratio = dev / baseline
            if ratio < best_ratio:
                best_ratio = ratio
                best_dev = dev
                
    return best_dev, baseline, best_ratio

# ==============================================================================
# 2. МАССИВНЫЙ АНАЛИЗ (m=3 ... 36)
# ==============================================================================
print("\n[*] Запуск гипер-сканирования одиночных гармоник (m=3 до m=36)...")
start_time = time.time()

single_results = []
for m in range(3, 37):
    _, dev, base, ratio = scan_single_m(m, angles)
    single_results.append((m, dev, base, ratio))

# Сортируем по коэффициенту топологического захвата (чем меньше, тем сильнее резонанс)
single_results.sort(key=lambda x: x[3])

print(f"[✓] Сканирование 34 гармоник завершено за {time.time() - start_time:.3f} сек.")
print("\n--- ТОП-5 ОДИНОЧНЫХ ГАРМОНИК (ОСНОВНЫЕ УЗЛЫ) ---")
for i in range(5):
    m, dev, base, ratio = single_results[i]
    status = "🔥 АБСОЛЮТНЫЙ ЗАХВАТ" if ratio < 0.90 else "⚠️ ЗАХВАТ"
    print(f"1 Место: " if i==0 else f"{i+1} Место: ", end="")
    print(f"m={m:<2} ({m*2} узлов) | Шум: {base:>5.2f}° | Факт: {dev:>5.2f}° | Коэф: {ratio:>5.3f} -> {status}")

# ==============================================================================
# 3. АНАЛИЗ ФРАКТАЛЬНЫХ СУПЕРПОЗИЦИЙ (m_1 ⊕ m_2)
# ==============================================================================
print("\n[*] Запуск сканирования фрактальных суперпозиций (Вложенные решетки)...")
nested_pairs = [
    (6, 12, "m=6 ⊕ 12 (Обертон Кубооктаэдра)"),
    (6, 18, "m=6 ⊕ 18 (Сложный резонанс)"),
    (6, 24, "m=6 ⊕ 24 (Глубокий фрактал)"),
    (12, 24, "m=12 ⊕ 24 (Мелкая решетка)"),
    (4, 6, "m=4 ⊕ 6 (Куб + Кубооктаэдр)")
]

start_time = time.time()
best_nested_ratio = 999
best_nested_str = ""

print("--- АУДИТ СМЕШАННЫХ СОСТОЯНИЙ ---")
for m1, m2, desc in nested_pairs:
    dev, base, ratio = scan_nested(m1, m2, angles)
    status = "🔥 ЖЕСТКИЙ" if ratio < 0.95 else ("❌ ХАОС" if ratio > 1.0 else "⚠️ СЛАБЫЙ")
    print(f"{desc:<32} | Шум: {base:>5.2f}° | Факт: {dev:>5.2f}° | Коэф: {ratio:>5.3f} -> {status}")
    
    if ratio < best_nested_ratio:
        best_nested_ratio = ratio
        best_nested_str = f"{desc} с коэф. {ratio:.3f}"

print("="*100)
best_single = single_results[0]
if best_single[3] < best_nested_ratio:
    print(f"🏆 ФИНАЛЬНЫЙ ВЕРДИКТ: Вакуум ПРЕДПОЧИТАЕТ чистую гармонику m={best_single[0]}")
else:
    print(f"🏆 ФИНАЛЬНЫЙ ВЕРДИКТ: Вакуум имеет ФРАКТАЛЬНУЮ структуру: {best_nested_str}")
print("="*100)