# -*- coding: utf-8 -*-
"""
GAPs collection CLI entry points.
"""
import glob
import logging
from warnings import warn

from rex import Resource
from gaps import Collector
from gaps.warnings import gapsWarning

logger = logging.getLogger(__name__)


def collect(
    collect_pattern="PIPELINE",
    project_points=None,
    datasets=None,
    purge_chunks=False,
):
    """Run collection on local worker.

    Collect data generated across multiple nodes into a single HDF5
    file.

    Parameters
    ----------
    collect_pattern : str | list | dict, optional
        Unix-style /filepath/pattern*.h5 representing the files to be
        collected into a single output HDF5 file. If no output file path
        is specified (i.e. this input is a single pattern or a list of
        patterns), the output file path will be inferred from the
        pattern itself (specifically, the wildcard will be removed
        and the result will be the output file path). If a list of
        patterns is provided, each pattern will be collected into a
        separate output file. To specify the name of the output file(s),
        set this input to a dictionary where the keys are paths to the
        output file (including the filename itself; relative paths are
        allowed) and the values are patterns representing the files that
        should be collected into the output file. If running a collect
        job as part of a pipeline, this input can be set to "PIPELINE",
        which will parse the output of the previous step and generate
        the input file pattern and output file name automatically.
        By default, ``"PIPELINE"``.
    project_points : str | list, optional
        This input should represent the project points that correspond
        to the *full collection* of points contained in the input HDF5
        files to be collected. You may simply point to a ProjectPoints
        csv file that contains the GID's that should be collected. You
        may also input the GID's as a list, though this may not be
        suitable for collections with a large number of points. You may
        also set this to input to ``None`` to generate a list of GID's
        automatically from the input files. By default, `None`.
    datasets : list of str, optional
        List of dataset names to collect into the output file. If
        collection is performed into multiple files (i.e. multiple input
        patterns), this list can contain all relevant datasets across
        all files (a warning wil be thrown, but it is safe to ignore
        it). If ``None``, all datasets from the input files are
        collected. By default, ``None``.
    purge_chunks : bool, optional
        Option to delete single-node input HDF5 files. Note that the
        input files will **not** be removed if any of the datasets they
        contain have not been collected, regardless of the value of this
        input. By default, ``False``.

    Returns
    -------
    str
        Path to HDF5 file with the collected outputs.
    """
    out, pattern = collect_pattern
    if "*" not in pattern:
        logger.info("Collect pattern has no wildcard! No collection performed")
        return str(out)

    logger.info(
        "Collection is being run with collection pattern: %s. Target output "
        "path is: %s",
        pattern,
        out,
    )

    datasets = _find_datasets(datasets, pattern)
    collector = Collector(out, pattern, project_points)
    for dataset_name in datasets:
        logger.debug("Collecting %r...", dataset_name)
        collector.collect(dataset_name)

    if purge_chunks:
        collector.purge_chunks()
    else:
        collector.move_chunks()

    return str(out)


def _find_datasets(datasets, pattern):
    """Find datasets from a sample file."""

    with Resource(glob.glob(pattern)[0]) as res:
        if datasets is None:
            return [
                d
                for d in res
                if not d.startswith("time_index") and d != "meta"
            ]
        missing = {d for d in datasets if d not in res}

    if any(missing):
        msg = (
            f"Could not find the following datasets in the output files: "
            f"{missing}. Skipping..."
        )
        warn(msg, gapsWarning)

    return list(set(datasets) - missing)
