#!/usr/bin/python3

r"""
    Generates a set of histograms Cherenkov photon distributions from CORSIKA output.

    The Cherenkov photons (from observation level) are read from a CORSIKA IACT
    output file provided as input.

    The histograms can be saved both into pdfs and in a hdf5 file.

    The following 2D histograms are generated:
        - Number of Cherenkov photons on the ground;
        - Density of Cherenkov photons on the ground;
        - Incoming direction (directive cosines) of the Cherenkov photons;
        - Time of arrival (ns) vs altitude of production (km);
        - Number of Cherenkov photons per event per telescope.

    The following 1D histograms are generated:
        - Wavelength;
        - Counts;
        - Density;
        - Time of arrival;
        - Altitude of production;
        - Number of photons per telescope;
        - Number of photons per event.

    Histograms for the distribution of CORSIKA event header elements can also be generated by using
    the --event_1d_histograms and --event_2d_histograms arguments. The accepted arguments (keys)
    are to be found in the CORSIKA manual, e.g., "total_energy", "zenith", "azimuth".

    Command line arguments
    ----------------------
    iact_file (str, required)
        The name of the CORSIKA IACT file resulted from the CORSIKA simulation.

    telescope_indices (list, optional)
        The list with the telescope indices to be considered in the generation of the histograms.
        Telescopes that are not in the list will not contribute with photons to the histograms.
        If the argument is not given, all telescopes are considered.

    individual_telescopes (bool, optional)
        Indicates whether single histograms are generated for the individual telescopes, or if
        a master histogram is generated for all the telescopes together.
        If the argument is not given, the Cherenkov photons from the given telescopes are considered
        together in the same histograms.

    hist_config (hdf5 or dict, optional)
        The configuration used for generating the histograms.
        It includes information about the bin sizes, the ranges, scale of the plot and units.
        By construction, three major histograms are created to start with:
        - hist_direction (2D): Directive cosines (x and y) for the incoming photons;
        - hist_position (3D): position x, position y, and wavelength;
        - hist_time_altitude (2D): time of arrival and altitude of emission;

    If the argument is not given, the default configuration is generated:

    .. code-block:: console

        hist_direction:
            x axis: {bins: 100, scale: linear, start: -1, stop: 1}
            y axis: {bins: 100, scale: linear, start: -1, stop: 1}

        hist_position:
            x axis:
                bins: 100
                scale: linear
                start: !astropy.units.Quantity
                    unit: &id001 m
                    value: -1000.0
                stop: &id002 !astropy.units.Quantity
                    unit: *id001
                    value: 1000.0
            y axis:
                bins: 100
                scale: linear
                start: !astropy.units.Quantity
                    unit: *id001
                    value: -1000.0
                stop: *id002
            z axis:
                bins: 80
                scale: linear
                start: !astropy.units.Quantity
                    unit: nm
                    value: 200.0
                stop: !astropy.units.Quantity
                    unit: *id003
                    value: 1000.0
        hist_time_altitude:
            x axis:
                bins: 100
                scale: linear
                start: !astropy.units.Quantity
                    unit: ns
                    value: -2000.0
                stop: !astropy.units.Quantity
                    unit: *id004
                    value: 2000.0
            y axis:
                bins: 100
                scale: linear
                start: !astropy.units.Quantity
                    unit: km
                    value: 120.0
                stop: !astropy.units.Quantity
                    unit: *id005
                    value: 0.0


    pdf (bool, optional)
        If set, histograms are saved into pdf files.
        One pdf file contains all the histograms for the Cherenkov photons.
        The name of the file is controlled via hdf5_file_name.
        If event_1d_histograms and event_2d_histograms are used, two separate pdf files might be
        created to accommodate the histograms for the CORSIKA event header elements. The core names
        of these output pdf files are also given by hdf5_file_name argument with the addition of
        'event_1d_histograms' and 'event_2d_histograms'.


    hdf5 (bool, optional)
        If set, histograms are saved into hdf5 files.

    hdf5_file_name (str, optional)
        The name of the output hdf5 data (without the path).
        It requires the --hdf5 flag.
        If not given, hdf5_file_name takes the name from the input IACT file (input_file).
        If the output hdf5_file_name file already exists, the tables associated to the chosen
        flags (e.g. hdf5, event_1d_histograms, event_2d_histograms) will be overwritten. The
        remaining tables, if any, will stay untouched.


    event_1d_histograms (str, optional)
        Generate 1D histograms for elements given in --event_1d_histograms from the CORSIKA event
        header and save into hdf5/pdf files.
        It allows more than one argument, separated by simple spaces.
        Usage: --event_1d_histograms first_interaction_height total_energy.

    event_2d_histograms (str, optional)
        Generate 2D histograms for elements given in --event_2d_histograms from the CORSIKA event
        header and save into hdf5/pdf files.
        It allows more than one argument, separated by simple spaces.
        The elements are grouped into pairs and the 2D histograms are generated always for two
        subsequent elements.
        For example, --event_2d_histograms first_interaction_height total_energy zenith azimuth
        will generate one 2D histogram for first_interaction_height total_energy and another 2D
        histogram for zenith and azimuth.

    Example
    -------
    Generate the histograms for a test IACT file:

     .. code-block:: console

        simtools-generate-corsika-histograms --iact_file /workdir/external/simtools/\\
        tests/resources/tel_output_10GeV-2-gamma-20deg-CTAO-South.corsikaio \\
            --pdf --hdf5 \\
            --event_2d_histograms zenith azimuth --event_1d_histograms total_energy

    Expected final print-out message:

    .. code-block:: console

        INFO::generate_corsika_histograms(l358)::main::Finalizing the application.
        Total time needed: 8s.
"""

import time

from simtools.application_control import get_application_label, startup_application
from simtools.configuration import configurator
from simtools.corsika.corsika_histograms import CorsikaHistograms


def _parse():
    """Parse command line configuration."""
    config = configurator.Configurator(
        label=get_application_label(__file__),
        description="Generate histograms for the Cherenkov photons saved in the CORSIKA IACT file.",
    )

    config.parser.add_argument(
        "--iact_file",
        help="Name of the CORSIKA IACT file from which to generate the histograms.",
        type=str,
        required=True,
    )

    config.parser.add_argument(
        "--telescope_indices",
        help="List of telescope indices to be considered in the generation of the histograms",
        type=str,
        required=False,
        nargs="+",
        default=None,
    )

    config.parser.add_argument(
        "--individual_telescopes",
        help="if False, the histograms are filled for all given telescopes together, otherwise"
        "one histogram is set for each telescope separately.",
        action="store_true",
        required=False,
        default=False,
    )

    config.parser.add_argument(
        "--hist_config",
        help="hdf5 file with the configuration parameters to create the histograms.",
        type=str,
        required=False,
        default=None,
    )

    config.parser.add_argument(
        "--pdf", help="Save histograms into a pdf file.", action="store_true", required=False
    )

    config.parser.add_argument(
        "--hdf5", help="Save histograms into hdf5 files.", action="store_true", required=False
    )

    config.parser.add_argument(
        "--hdf5_file_name",
        help="Name of the hdf5 file where to save the histograms.",
        type=str,
        required=False,
        default=None,
    )

    config.parser.add_argument(
        "--event_1d_histograms",
        help="The keys from the CORSIKA event header to be used for the generation of 1D "
        "histograms. The available choices can been found in the all_event_keys attribute of"
        "the CorsikaHistograms.",
        required=False,
        default=None,
        nargs="*",
    )

    config.parser.add_argument(
        "--event_2d_histograms",
        help="The keys from the CORSIKA event header to be used for the generation of 2D "
        "histograms. The available choices can been found in the all_event_keys attribute of"
        "the CorsikaHistograms.",
        required=False,
        default=None,
        nargs="*",
    )

    config_parser, _ = config.initialize(db_config=False, paths=True)

    if (
        not config_parser["pdf"]
        and not config_parser["hdf5"]
        and not config_parser["event_1d_histograms"]
        and not config_parser["event_2d_histograms"]
    ):
        config.parser.error(
            "At least one argument is required: --pdf, --hdf5, --event_1d_histograms, or "
            "--event_2d_histograms."
        )

    return config_parser, _


def main():
    """Generate a set of histograms for the Cherenkov photons saved in the CORSIKA IACT file."""
    app_context = startup_application(_parse)

    initial_time = time.time()

    corsika_histograms_instance = CorsikaHistograms(
        app_context.args["iact_file"],
        output_path=app_context.io_handler.get_output_directory(),
        hdf5_file_name=app_context.args["hdf5_file_name"],
    )
    corsika_histograms_instance.run_export_pipeline(
        individual_telescopes=app_context.args["individual_telescopes"],
        hist_config=app_context.args["hist_config"],
        indices_arg=app_context.args["telescope_indices"],
        write_pdf=app_context.args["pdf"],
        write_hdf5=app_context.args["hdf5"],
        event1d=app_context.args["event_1d_histograms"],
        event2d=app_context.args["event_2d_histograms"],
        test=app_context.args["test"],
    )

    final_time = time.time()
    app_context.logger.info(
        f"Finalizing the application. Total time needed: {round(final_time - initial_time)}s."
    )


if __name__ == "__main__":
    main()
