"""
Improved Mie Scattering Model for Snow Particles
Snow Dust Project – Optical Visibility Physics
SciPy-free, physically consistent transition model
"""

import numpy as np
from dataclasses import dataclass


@dataclass
class ScatteringResult:
    Q_sca: float
    Q_ext: float
    g: float              # Asymmetry parameter
    sigma_ext: float      # Extinction cross section (m²)


class SnowMieScattering:

    def __init__(self, wavelength=550e-9):
        self.wavelength = wavelength  # green light (m)

    # ==========================================================
    # PUBLIC INTERFACE
    # ==========================================================
    def compute(self, diameter, refractive_index=1.31):
        r = diameter / 2
        x = 2 * np.pi * r / self.wavelength  # size parameter

        if x < 1:
            return self._rayleigh(r, refractive_index)

        elif x < 2000:
            return self._mie_transition(r, x)

        else:
            return self._geometric(r)

    # ==========================================================
    # RAYLEIGH REGIME (x << 1)
    # ==========================================================
    def _rayleigh(self, r, m):
        x = 2 * np.pi * r / self.wavelength
        Q_sca = (8/3) * x**4 * abs((m**2 - 1)/(m**2 + 2))**2
        Q_ext = Q_sca
        g = 0.0
        sigma_ext = Q_ext * np.pi * r**2
        return ScatteringResult(Q_sca, Q_ext, g, sigma_ext)

    # ==========================================================
    # TRANSITION REGIME (Mie-like for snow)
    # ==========================================================
    def _mie_transition(self, r, x):
        # Smooth interpolation between Rayleigh and Geometric
        Q_ray = (8/3) * x**4 * 0.01  # small factor for tiny x
        Q_geo = 2.0
        transition = 1 - np.exp(-0.12 * x)
        Q_sca = Q_ray * np.exp(-0.08 * x) + Q_geo * transition
        Q_ext = Q_sca
        g = 0.15 + 0.7 * (1 - np.exp(-x/8))
        sigma_ext = Q_ext * np.pi * r**2
        return ScatteringResult(Q_sca, Q_ext, g, sigma_ext)

    # ==========================================================
    # GEOMETRIC OPTICS (x >> 1)
    # ==========================================================
    def _geometric(self, r):
        Q_sca = 2.0
        Q_ext = 2.0
        g = 0.87
        sigma_ext = Q_ext * np.pi * r**2
        return ScatteringResult(Q_sca, Q_ext, g, sigma_ext)

    # ==========================================================
    # CALCULATE VISIBILITY
    # ==========================================================
    def visibility(self, snow_density, diameter):
        result = self.compute(diameter)
        beta_ext = snow_density * result.sigma_ext
        if beta_ext > 0:
            return 3.912 / beta_ext  # Koschmieder formula
        else:
            return float('inf')


# ==============================================================
# TEST SCRIPT
# ==============================================================
if __name__ == "__main__":
    mie = SnowMieScattering()

    print("Testing Improved Mie Scattering (SciPy-free)\n")

    for d in [10e-6, 200e-6, 1e-3]:
        res = mie.compute(d)
        print(f"Particle {d*1e6:.0f} µm → Q_sca={res.Q_sca:.3f}, g={res.g:.2f}")

    vis = mie.visibility(1e6, 200e-6)
    print(f"\nVisibility in snowstorm: {vis:.1f} m")
    print("\nModule ready (Termux-compatible, physics-consistent).")
