r"""
**Telluric**
-----------------
Functionality pertaining to telluric synthetic spectra from skycalc (Noll et al. 2012, Jones et al. 2013) and TelFit (Gullikson et al. 2014).
"""

from warnings import filterwarnings
from logging import getLogger
from gollum.precomputed_spectrum import PrecomputedSpectrum
from astropy.utils.exceptions import AstropyDeprecationWarning
from astropy import units as u
from pandas import read_csv, to_numeric

log = getLogger(__name__)

#  See Issue: https://github.com/astropy/specutils/issues/779
filterwarnings("ignore", category=AstropyDeprecationWarning)
# See Issue: https://github.com/astropy/specutils/issues/800
filterwarnings("ignore", category=RuntimeWarning)


## TODO: rename this to SkyCalc??
class TelluricSpectrum(PrecomputedSpectrum):
    r"""
    A container for a single Telluric precomputed synthetic spectrum, currently from the skycalc website at eso.org.

    Parameters
    ----------
    path : str
        The path to a whitespace-delimited ASCII file generated by skycalc on eso.org.  You can either provide the file locally or a weblink. Defaults to a demo spectrum
    wl_lo : float
        The shortest wavelength of the models to keep (Angstroms)
    wl_hi : float
        The longest wavelength of the models to keep (Angstroms)
    """

    def __init__(
        self,
        *args,
        path="https://gist.githubusercontent.com/gully/b93a04ede17f617d36b2a8ffc32a60e6/raw/01c603ee201509b79b1a464093e6200ae2032198/demo_skycalc_telluric_transmission_spectrum.txt",
        wl_lo=8038,
        wl_hi=12849,
        **kwargs,
    ):
        if path:
            # Units: nm, transmittance
            df_native = (
                read_csv(
                    path,
                    sep=r"\s+",
                    names=["wavelength_nm", "transmittance"],
                )
                .sort_values("wavelength_nm")
                .reset_index(drop=True)
            )

            # convert to Angstrom
            df_native["wavelength"] = df_native["wavelength_nm"] * 10.0
            mask = (df_native.wavelength > wl_lo) & (df_native.wavelength < wl_hi)
            df_trimmed = df_native[mask].reset_index(drop=True)

            super().__init__(
                spectral_axis=df_trimmed.wavelength.values * u.AA,
                flux=df_trimmed.transmittance.values * u.dimensionless_unscaled,
                **kwargs,
            )

        else:
            super().__init__(*args, **kwargs)


class TelFitSpectrum(PrecomputedSpectrum):
    r"""
    A container for a single TelFit precomputed synthetic spectrum.

    Parameters
    ----------
    path : str
        The path to a whitespace-delimited ASCII file generated by skycalc on eso.org.  You can either provide the file locally or a weblink.  'default' uses a demo spectrum
    wl_lo : float
        The shortest wavelength of the models to keep (Angstroms)
    wl_hi : float
        The longest wavelength of the models to keep (Angstroms)
    """

    def __init__(self, *args, path=None, **kwargs):
        if path:
            names = ["wavelength_nm", "transmission", "continuum", "err"]
            df_native = read_csv(
                path,
                sep=r"\s+",
                names=names,
                usecols=names[0:2],
                encoding="unicode_escape",  # or UTF-8?
                low_memory=False,
            )

            # Units: nm, transmittance
            # convert to Angstrom
            df_native["wavelength"] = (
                to_numeric(df_native["wavelength_nm"], errors="coerce") * 10.0
            )
            flux_out = to_numeric(df_native["transmission"], errors="coerce")

            good_mask = (df_native.wavelength.values == df_native.wavelength.values) & (
                flux_out.values == flux_out.values
            )

            super().__init__(
                spectral_axis=df_native.wavelength.values[good_mask] * u.AA,
                flux=flux_out.values[good_mask] * u.dimensionless_unscaled,
                **kwargs,
            )

        else:
            super().__init__(*args, **kwargs)

    def air_to_vacuum(self):
        """Converts a spectrum from air to vacuum

        Based on Morton, D. C. 1991, ApJS, 77, 119
        Returns
        -------
        vaccum_spectrum: TelFitSpectrum
            The spectrum in vacuum
        """
        wave_A = self.wavelength.to(u.AA).value
        n_air = (
            1.0
            + 2.735182e-4
            + 131.4182 / (w2 := wave_A * wave_A)
            + 2.76249e8 / (w2 * w2)
        )
        return self._copy(spectral_axis=self.wavelength * n_air, wcs=None)
