#!/usr/bin/env python3
"""
نموذج عددي دقيق كامل للعاصفة الثلجية
Snow Dust Project - حل تفاضلي بتقنية RK4
"""

import numpy as np
from dataclasses import dataclass, field
from typing import Dict, List, Tuple
import time

print("="*80)
print("🧮 النموذج العددي الدقيق الكامل للعاصفة الثلجية")
print("Snow Dust Project - حل RK4 مع معادلات تفاضلية كاملة")
print("="*80)

# ============================================
# هياكل البيانات الدقيقة
# ============================================
@dataclass
class TimeStep:
    """حالة النظام في خطوة زمنية واحدة"""
    t: float                    # الزمن [s]
    ρ_p: float                  # كثافة الجسيمات [particles/m³]
    v_p: np.ndarray            # سرعة الجسيمات [m/s] - (vx, vy, vz)
    v_wind: np.ndarray         # سرعة الرياح [m/s]
    E_field: np.ndarray        # المجال الكهربائي [V/m]
    ΔT: float                  # فرق الحرارة [K]
    d_p: float                 # قطر الجسيم [m]
    q_p: float                 # شحنة الجسيم [C]
    position: np.ndarray       # الموقع [m]
    visibility: float          # الرؤية [m]
    signal_strength: float     # قوة إشارة الملاحة [0-1]
    nav_viable: bool           # هل الملاحة ممكنة؟
    
    def __post_init__(self):
        """تهيئة المصفوفات"""
        if isinstance(self.v_p, list):
            self.v_p = np.array(self.v_p, dtype=float)
        if isinstance(self.v_wind, list):
            self.v_wind = np.array(self.v_wind, dtype=float)
        if isinstance(self.E_field, list):
            self.E_field = np.array(self.E_field, dtype=float)
        if isinstance(self.position, list):
            self.position = np.array(self.position, dtype=float)

# ============================================
# فئة الحل العددي الكاملة
# ============================================
class NumericalSnowstormSolver:
    """
    حل النظام التفاضلي باستخدام RK4
    """
    
    def __init__(self):
        # الثوابت الفيزيائية الدقيقة
        self.g = np.array([0.0, 0.0, -9.80665])  # تسارع الجاذبية [m/s²]
        self.ε0 = 8.854187817e-12                # سماحية الفراغ [F/m]
        self.η_air = 1.72e-5                     # لزوجة الهواء [Pa·s]
        self.α_air = 1.9e-5                      # نفوذية حرارية [m²/s]
        self.ρ_ice = 917                         # كثافة الجليد [kg/m³]
        self.kB = 1.380649e-23                   # ثابت بولتزمان [J/K]
        
        # شروط الابتدائية REALISTIC
        self.initial_state = TimeStep(
            t=0.0,
            ρ_p=1.0e6,                          # مليون جسيم/م³
            v_p=[0.0, 0.0, -1.0],               # سقوط حر
            v_wind=[15.0, 0.0, 0.0],            # رياح غربية
            E_field=[0.0, 0.0, 0.0],
            ΔT=7.5,
            d_p=200e-6,
            q_p=5.0e-14,                        # 50 فمتوكولوم REALISTIC!
            position=[0.0, 0.0, 1000.0],
            visibility=0.0,
            signal_strength=0.0,
            nav_viable=False
        )
        
        # معاملات النموذج
        self.σ_ext = 2.0 * np.pi * (100e-6)**2   # مقطع الامتصاص [m²]
        self.S_p = 5.0e5                         # معدل سقوط ثلج [particles/(m³·s)]
        self.L_p = 0.15                          # معامل الترسيب [1/s]
        self.R0 = 10000.0                        # رؤية قصوى [m]
        self.E_max = 10000.0                     # أقصى مجال متوقع [V/m]
        self.R_max = 1000.0                      # أقصى رؤية مفيدة [m]
        self.R_cloud = 500.0                     # نصف قطر سحابة العاصفة [m]
        
    # ========================================
    # دالة المعدلات f(y, t) للنظام
    # ========================================
    def system_rates(self, state: TimeStep) -> Dict:
        """
        حساب جميع المعدلات التفاضلية دفعة واحدة
        """
        # 1. معدل تغير كثافة الجسيمات: dρ_p/dt = -∇·(ρ_p v) + S_p - L_p
        divergence = 0.1 * state.ρ_p * state.v_wind[0]  # ∇·(ρ_p v) ≈ ∂/∂x
        dρ_dt = -divergence + self.S_p - self.L_p * state.ρ_p
        
        # 2. معدل تغير سرعة الجسيمات: dv_p/dt = g - (6πηr_p/m_p)(v_p - v_wind) + (q_p/m_p)E
        r_p = state.d_p / 2.0
        m_p = (4.0/3.0) * np.pi * r_p**3 * self.ρ_ice
        drag_coeff = (6.0 * np.pi * self.η_air * r_p) / m_p
        
        dv_dt = (self.g - drag_coeff * (state.v_p - state.v_wind) + 
                (state.q_p / m_p) * state.E_field)
        
        # 3. معدل تغير فرق الحرارة: dΔT/dt = -v·∇ΔT + α∇²ΔT
        convection = 0.01 * np.linalg.norm(state.v_wind) * state.ΔT
        diffusion = -self.α_air * state.ΔT / 100.0
        dΔT_dt = -convection + diffusion
        
        # 4. تحديث المجال الكهربائي: E = (q_p ρ_p R_cloud) / (3ε₀)
        ρ_e = state.ρ_p * state.q_p  # كثافة شحنة الفراغ [C/m³]
        E_z = (ρ_e * self.R_cloud) / (3.0 * self.ε₀)
        
        # إضافة تقلبات مكانية (واقعية)
        E_x = 0.05 * E_z * np.random.randn()
        E_y = 0.05 * E_z * np.random.randn()
        E_field_new = np.array([E_x, E_y, E_z])
        
        # 5. الرؤية: R = R₀ exp(-σ_ext ρ_p)
        τ = self.σ_ext * state.ρ_p  # العمق البصري
        visibility = self.R0 * np.exp(-τ) if τ < 100 else 0.1
        
        # 6. قوة إشارة الملاحة: S = (|E|/E_max) × (R/R_max)
        E_mag = np.linalg.norm(state.E_field)
        signal = (E_mag / self.E_max) * (visibility / self.R_max)
        signal = max(0.0, min(1.0, signal))  # تطبيع بين 0 و 1
        
        return {
            'dρ_dt': dρ_dt,
            'dv_dt': dv_dt,
            'dΔT_dt': dΔT_dt,
            'E_field': E_field_new,
            'visibility': visibility,
            'signal_strength': signal,
            'nav_viable': signal > 0.3
        }
    
    # ========================================
    # طريقة رونج-كوتا من الدرجة الرابعة (RK4)
    # ========================================
    def rk4_step(self, state: TimeStep, dt: float) -> TimeStep:
        """
        خطوة RK4 دقيقة للنظام التفاضلي
        """
        # k1 = f(t, y)
        k1 = self.system_rates(state)
        
        # الحالة الوسيطة 1
        state_k2 = TimeStep(
            t=state.t + dt/2,
            ρ_p=state.ρ_p + dt/2 * k1['dρ_dt'],
            v_p=state.v_p + dt/2 * k1['dv_dt'],
            v_wind=state.v_wind.copy(),
            E_field=k1['E_field'],
            ΔT=state.ΔT + dt/2 * k1['dΔT_dt'],
            d_p=state.d_p,
            q_p=state.q_p,
            position=state.position + dt/2 * state.v_p,
            visibility=0,
            signal_strength=0,
            nav_viable=False
        )
        
        # k2 = f(t + dt/2, y + dt/2 * k1)
        k2 = self.system_rates(state_k2)
        
        # الحالة الوسيطة 2
        state_k3 = TimeStep(
            t=state.t + dt/2,
            ρ_p=state.ρ_p + dt/2 * k2['dρ_dt'],
            v_p=state.v_p + dt/2 * k2['dv_dt'],
            v_wind=state.v_wind.copy(),
            E_field=k2['E_field'],
            ΔT=state.ΔT + dt/2 * k2['dΔT_dt'],
            d_p=state.d_p,
            q_p=state.q_p,
            position=state.position + dt/2 * state.v_p + dt/4 * k1['dv_dt'],
            visibility=0,
            signal_strength=0,
            nav_viable=False
        )
        
        # k3 = f(t + dt/2, y + dt/2 * k2)
        k3 = self.system_rates(state_k3)
        
        # الحالة الوسيطة 3
        state_k4 = TimeStep(
            t=state.t + dt,
            ρ_p=state.ρ_p + dt * k3['dρ_dt'],
            v_p=state.v_p + dt * k3['dv_dt'],
            v_wind=state.v_wind.copy(),
            E_field=k3['E_field'],
            ΔT=state.ΔT + dt * k3['dΔT_dt'],
            d_p=state.d_p,
            q_p=state.q_p,
            position=state.position + dt * state.v_p + dt/2 * k2['dv_dt'],
            visibility=0,
            signal_strength=0,
            nav_viable=False
        )
        
        # k4 = f(t + dt, y + dt * k3)
        k4 = self.system_rates(state_k4)
        
        # الجمع النهائي: y_{n+1} = y_n + (dt/6)(k1 + 2k2 + 2k3 + k4)
        ρ_p_new = state.ρ_p + (dt/6) * (k1['dρ_dt'] + 2*k2['dρ_dt'] + 2*k3['dρ_dt'] + k4['dρ_dt'])
        v_p_new = state.v_p + (dt/6) * (k1['dv_dt'] + 2*k2['dv_dt'] + 2*k3['dv_dt'] + k4['dv_dt'])
        ΔT_new = state.ΔT + (dt/6) * (k1['dΔT_dt'] + 2*k2['dΔT_dt'] + 2*k3['dΔT_dt'] + k4['dΔT_dt'])
        
        # تحديث المجال الكهربائي من k4 (الأكثر دقة)
        E_field_new = k4['E_field']
        
        # تحديث الرؤية وقوة الإشارة
        visibility_new = k4['visibility']
        signal_new = k4['signal_strength']
        nav_viable_new = k4['nav_viable']
        
        # تحديث الموقع
        position_new = state.position + dt * v_p_new
        
        # إضافة تقلبات واقعية في الرياح وشحنة الجسيمات
        if np.random.random() < 0.1:  # 10% احتمال لتغير الرياح
            wind_factor = np.random.uniform(0.9, 1.1)
            v_wind_new = state.v_wind * wind_factor
        else:
            v_wind_new = state.v_wind.copy()
        
        if np.random.random() < 0.05:  # 5% احتمال لتغير الشحنة
            q_p_new = state.q_p * np.random.uniform(0.8, 1.2)
        else:
            q_p_new = state.q_p
        
        # إنشاء الحالة الجديدة
        new_state = TimeStep(
            t=state.t + dt,
            ρ_p=max(ρ_p_new, 1e4),  # الحد الأدنى 10,000 جسيم/م³
            v_p=v_p_new,
            v_wind=v_wind_new,
            E_field=E_field_new,
            ΔT=max(ΔT_new, 0.1),    # الحد الأدنى 0.1 كلفن
            d_p=state.d_p,
            q_p=q_p_new,
            position=position_new,
            visibility=visibility_new,
            signal_strength=signal_new,
            nav_viable=nav_viable_new
        )
        
        return new_state
    
    # ========================================
    # حل النظام الكامل
    # ========================================
    def solve(self, t_end: float = 300.0, dt: float = 1.0) -> List[TimeStep]:
        """
        حل النظام التفاضلي الكامل
        """
        print("\n🧮 بدء الحل العددي باستخدام RK4...")
        print(f"   المدة: {t_end} ثانية")
        print(f"   خطوة زمنية: {dt} ثانية")
        print("-"*60)
        
        # التحقق من ثبات RK4
        if dt > 0.5:
            print("⚠️  تحذير: خطوة زمنية كبيرة، قد تفقد الدقة")
        
        n_steps = int(t_end / dt) + 1
        states = []
        
        # الحالة الابتدائية
        current_state = self.initial_state
        initial_rates = self.system_rates(current_state)
        current_state.visibility = initial_rates['visibility']
        current_state.signal_strength = initial_rates['signal_strength']
        current_state.nav_viable = initial_rates['nav_viable']
        
        states.append(current_state)
        
        # التكرار الزمني
        for step in range(1, n_steps):
            # خطوة RK4
            current_state = self.rk4_step(current_state, dt)
            states.append(current_state)
            
            # عرض التقدم
            if step % 30 == 0:
                print(f"   ⏱️  t = {current_state.t:5.1f}s | ρ_p = {current_state.ρ_p/1e6:5.2f}M/m³ | "
                      f"R = {current_state.visibility:5.1f}m | E = {np.linalg.norm(current_state.E_field):6.1f}V/m | "
                      f"S = {current_state.signal_strength:.3f}")
        
        print("-"*60)
        print("✅ اكتمل الحل العددي!")
        
        return states
    
    # ========================================
    # تحليل النتائج
    # ========================================
    def analyze_results(self, states: List[TimeStep]):
        """
        تحليل إحصائي للنتائج
        """
        print("\n📊 تحليل النتائج الإحصائي:")
        print("="*60)
        
        # استخراج البيانات
        times = [s.t for s in states]
        densities = [s.ρ_p for s in states]
        visibilities = [s.visibility for s in states]
        e_fields = [np.linalg.norm(s.E_field) for s in states]
        signals = [s.signal_strength for s in states]
        nav_viable = [s.nav_viable for s in states]
        
        # الإحصائيات
        nav_percentage = sum(nav_viable) / len(nav_viable) * 100
        
        print(f"   متوسط كثافة الجسيمات: {np.mean(densities)/1e6:.2f} ± {np.std(densities)/1e6:.2f} M/m³")
        print(f"   متوسط الرؤية: {np.mean(visibilities):.1f} ± {np.std(visibilities):.1f} m")
        print(f"   متوسط المجال الكهربائي: {np.mean(e_fields):.1f} ± {np.std(e_fields):.1f} V/m")
        print(f"   متوسط قوة الإشارة: {np.mean(signals):.3f} ± {np.std(signals):.3f}")
        print(f"   نسبة الوقت المناسب للملاحة: {nav_percentage:.1f}%")
        
        # تقييم نظام الملاحة
        if nav_percentage > 70:
            print(f"\n🎯 نظام Snow Dust: ✅ جاهز للعمل")
            print("   يمكن الاعتماد على النظام للملاحة في معظم الظروف")
        elif nav_percentage > 30:
            print(f"\n🎯 نظام Snow Dust: ⚠️  محدود العمل")
            print("   يحتاج إلى دعم GPS في بعض الأوقات")
        else:
            print(f"\n🎯 نظام Snow Dust: ❌ محدود جداً")
            print("   يحتاج إلى تحسين حساسية المستشعرات")
        
        print("="*60)
        
        return {
            'times': times,
            'densities': densities,
            'visibilities': visibilities,
            'e_fields': e_fields,
            'signals': signals,
            'nav_viable': nav_viable
        }

# ============================================
# التنفيذ الرئيسي
# ============================================
def main():
    """الدالة الرئيسية"""
    # إنشاء المحلل
    solver = NumericalSnowstormSolver()
    
    # حل النظام
    start_time = time.time()
    states = solver.solve(t_end=300.0, dt=0.5)  # 5 دقائق محاكاة
    end_time = time.time()
    
    print(f"\n⏱️  وقت التنفيذ: {end_time - start_time:.2f} ثانية")
    
    # تحليل النتائج
    results = solver.analyze_results(states)
    
    # عرض عينة من البيانات
    print("\n📋 عينة من البيانات (كل 30 ثانية):")
    print("-"*80)
    print(f"{'الزمن (s)':>10} {'الكثافة (M/m³)':>15} {'الرؤية (m)':>12} {'E-field (V/m)':>15} {'الإشارة':>8} {'ملاحة':>8}")
    print("-"*80)
    
    for i, state in enumerate(states):
        if i % 60 == 0:  # كل 30 ثانية (60 خطوة × 0.5 ثانية)
            print(f"{state.t:10.1f} {state.ρ_p/1e6:15.2f} {state.visibility:12.1f} "
                  f"{np.linalg.norm(state.E_field):15.1f} {state.signal_strength:8.3f} "
                  f"{'✅' if state.nav_viable else '❌':>8}")
    
    print("-"*80)
    
    # تقرير ختامي
    final_state = states[-1]
    print(f"\n🎯 الحالة النهائية عند t = {final_state.t:.1f}s:")
    print(f"   الموقع: {final_state.position} m")
    print(f"   سرعة الرياح: {final_state.v_wind} m/s")
    print(f"   شحنة الجسيم: {final_state.q_p:.2e} C")
    print(f"   فرق الحرارة: {final_state.ΔT:.1f} K")
    print(f"   قطر الجسيم: {final_state.d_p*1e6:.1f} µm")
    
    # تقييم الفيزياء
    print(f"\n🔬 تقييم الفيزياء:")
    
    # طاقة الحركة
    r_p = final_state.d_p / 2
    m_p = (4/3) * np.pi * r_p**3 * solver.ρ_ice
    kinetic_energy = 0.5 * m_p * np.linalg.norm(final_state.v_p)**2
    print(f"   طاقة حركة الجسيم: {kinetic_energy:.2e} J")
    
    # الطاقة الكهربائية
    electric_potential = np.linalg.norm(final_state.E_field) * 2*r_p
    electric_energy = final_state.q_p * electric_potential
    print(f"   طاقة كهربائية للجسيم: {electric_energy:.2e} J")
    
    # نسبة الطاقة
    if kinetic_energy > 0:
        energy_ratio = electric_energy / kinetic_energy
        print(f"   نسبة الطاقة الكهربائية/الحركية: {energy_ratio:.2e}")
        
        if energy_ratio > 0.1:
            print(f"   ⚡ التأثير الكهربائي مهم!")
        else:
            print(f"   ⚡ التأثير الكهربائي ضعيف")
    
    print("\n" + "="*80)
    print("✅ النموذج العددي الدقيق مكتمل وجاهز للاستخدام العلمي")
    print("="*80)

if __name__ == "__main__":
    main()
