"""
Physical constants for spin wave calculations.

Based on CODATA 2018 recommended values.
"""

import numpy as np


class Constants:
    """Physical constants for spin wave calculations."""
    
    # Planck constant (meV·s)
    h = 4.135667696e-12  # meV·s
    hbar = h / (2 * np.pi)  # meV·s
    
    # Boltzmann constant
    kB = 8.617333262e-2  # meV/K
    
    # Bohr magneton
    muB = 5.7883818060e-2  # meV/T
    
    # Neutron mass
    m_n = 1.67492749804e-27  # kg
    
    # Gyromagnetic ratio of neutron
    gamma_n = -1.91304273  # dimensionless (in units of nuclear magneton)
    
    # Classical electron radius
    r0 = 2.8179403262e-15  # m
    
    # Speed of light
    c = 299792458  # m/s
    
    # Conversion factors
    A_to_nm = 0.1  # Angstrom to nm
    meV_to_THz = 0.24180  # meV to THz
    meV_to_K = 11.6045  # meV to Kelvin
    
    # Neutron scattering length
    # Prefactor for neutron scattering cross section
    # (gamma * r0 / 2)^2 in barn
    neutron_prefactor = (gamma_n * r0 / 2)**2 * 1e28  # barn
    
    @classmethod
    def wavelength_to_energy(cls, wavelength: float) -> float:
        """
        Convert neutron wavelength (Å) to energy (meV).
        
        E = h^2 / (2 * m_n * lambda^2)
        """
        # E = 81.81 / lambda^2 (in meV for lambda in Å)
        return 81.81 / wavelength**2
    
    @classmethod
    def energy_to_wavelength(cls, energy: float) -> float:
        """
        Convert energy (meV) to neutron wavelength (Å).
        """
        return np.sqrt(81.81 / energy)
    
    @classmethod
    def k_to_energy(cls, k: float) -> float:
        """
        Convert wavevector (Å^-1) to energy (meV).
        
        E = hbar^2 * k^2 / (2 * m_n)
        """
        # E = 2.072 * k^2 (in meV for k in Å^-1)
        return 2.072 * k**2
    
    @classmethod
    def q_to_d(cls, Q: float) -> float:
        """
        Convert Q (Å^-1) to d-spacing (Å).
        
        d = 2*pi / Q
        """
        return 2 * np.pi / Q


# Singleton instance
CONSTANTS = Constants()


# Unit conversions
def meV_to_K(E):
    """Convert meV to Kelvin."""
    return E * CONSTANTS.meV_to_K

def K_to_meV(T):
    """Convert Kelvin to meV."""
    return T / CONSTANTS.meV_to_K

def meV_to_THz(E):
    """Convert meV to THz."""
    return E * CONSTANTS.meV_to_THz

def THz_to_meV(f):
    """Convert THz to meV."""
    return f / CONSTANTS.meV_to_THz
