"""
Functions for reading NEXRAD Level 3 products.

"""

import numpy as np

from ..config import FileMetadata, get_fillvalue
from ..core.radar import Radar
from .common import _test_arguments, make_time_unit_str, prepare_for_read
from .nexrad_level3 import NEXRADLevel3File


def read_nexrad_level3(
    filename,
    field_names=None,
    additional_metadata=None,
    file_field_names=False,
    exclude_fields=None,
    include_fields=None,
    storage_options={"anon": True},
    **kwargs
):
    """
    Read a NEXRAD Level 3 product.

    Parameters
    ----------
    filename : str
        Filename of NEXRAD Level 3 product file. The files hosted by
        at the NOAA National Climate Data Center [1]_ as well as on the
        NWS WSR-88D Level III Data Collection and Distribution Network
        have been tests. Other NEXRAD Level 3 files may or may not work.
        A file-like object pointing to the beginning of such a file is also
        supported [2]_.
    field_names : dict, optional
        Dictionary mapping NEXRAD level 3 product number to radar field names.
        If the product number of the file does not appear in this dictionary
        or has a value of None it will not be placed in the radar.fields
        dictionary. A value of None, the default, will use the mapping
        defined in the metadata configuration file.
    additional_metadata : dict of dicts, optional
        Dictionary of dictionaries to retrieve metadata from during this read.
        This metadata is not used during any successive file reads unless
        explicitly included. A value of None, the default, will not
        introduct any addition metadata and the file specific or default
        metadata as specified by the metadata configuration file will be used.
    file_field_names : bool, optional
        True to use the product number for the field name. In this case the
        field_names parameter is ignored. The field dictionary will likely
        only have a 'data' key, unless the fields are defined in
        `additional_metadata`.
    exclude_fields : list or None, optional
        List of fields to exclude from the radar object. This is applied
        after the `file_field_names` and `field_names` parameters. Set
        to None to include all fields specified by include_fields.
    include_fields : list or None, optional
        List of fields to include from the radar object. This is applied
        after the `file_field_names` and `field_names` parameters. Set
        to None to include all fields not specified by exclude_fields.
    **kwargs
        Additional keyword arguments to pass to fsspec to open the dataset

    Returns
    -------
    radar : Radar
        Radar object containing all moments and sweeps/cuts in the volume.
        Gates not collected are masked in the field data.

    References
    ----------
    .. [1] http://www.ncdc.noaa.gov/
    .. [2] http://www.roc.noaa.gov/wsr88d/Level_III/Level3Info.asp

    """
    # test for non empty kwargs
    _test_arguments(kwargs)

    # create metadata retrieval object
    filemetadata = FileMetadata(
        "nexrad_level3",
        field_names,
        additional_metadata,
        file_field_names,
        exclude_fields,
        include_fields,
    )

    # open the file
    nfile = NEXRADLevel3File(
        prepare_for_read(filename, storage_options=storage_options)
    )
    nradials = nfile.packet_header["nradials"]
    msg_code = nfile.msg_header["code"]

    # time
    time = filemetadata("time")
    time_start = nfile.get_volume_start_datetime()
    time["units"] = make_time_unit_str(time_start)
    time["data"] = np.zeros((nradials,), dtype="float64")

    # range
    _range = filemetadata("range")
    _range["data"] = nfile.get_range()
    _range["meters_to_center_of_first_gate"] = _range["data"][0]
    _range["meters_between_gates"] = _range["data"][1] - _range["data"][0]

    # fields
    fields = {}
    field_name = filemetadata.get_field_name(msg_code)
    if field_name is None:
        fields = {}
    else:
        dic = filemetadata(field_name)
        dic["_FillValue"] = get_fillvalue()
        dic["data"] = nfile.get_data()
        fields = {field_name: dic}

    # metadata
    metadata = filemetadata("metadata")
    metadata["original_container"] = "NEXRAD Level 3"

    # scan_type
    scan_type = "ppi"

    # latitude, longitude, altitude
    latitude = filemetadata("latitude")
    longitude = filemetadata("longitude")
    altitude = filemetadata("altitude")

    lat, lon, height = nfile.get_location()
    # Nexrad altitude is in feet, convert to meters unless user's
    # default config has units in feet.
    if altitude["units"] == "meters":
        height = height * 0.3048
    latitude["data"] = np.array([lat], dtype="float64")
    longitude["data"] = np.array([lon], dtype="float64")
    altitude["data"] = np.array([height], dtype="float64")

    # sweep_number, sweep_mode, fixed_angle, sweep_start_ray_index
    # sweep_end_ray_index
    sweep_number = filemetadata("sweep_number")
    sweep_mode = filemetadata("sweep_mode")
    sweep_start_ray_index = filemetadata("sweep_start_ray_index")
    sweep_end_ray_index = filemetadata("sweep_end_ray_index")

    sweep_number["data"] = np.array([0], dtype="int32")
    sweep_mode["data"] = np.array(1 * ["azimuth_surveillance"], dtype="S")

    sweep_start_ray_index["data"] = np.array([0], dtype="int32")
    sweep_end_ray_index["data"] = np.array([nradials - 1], dtype="int32")

    # azimuth, elevation, fixed_angle
    azimuth = filemetadata("azimuth")
    elevation = filemetadata("elevation")
    fixed_angle = filemetadata("fixed_angle")
    azimuth["data"] = nfile.get_azimuth()
    elev = nfile.get_elevation()
    elevation["data"] = np.ones((nradials,), dtype="float32") * elev
    fixed_angle["data"] = np.array([elev], dtype="float32")

    nfile.close()
    return Radar(
        time,
        _range,
        fields,
        metadata,
        scan_type,
        latitude,
        longitude,
        altitude,
        sweep_number,
        sweep_mode,
        fixed_angle,
        sweep_start_ray_index,
        sweep_end_ray_index,
        azimuth,
        elevation,
        instrument_parameters=None,
    )
