import os

from serenata_toolbox.datasets.downloader import Downloader
from serenata_toolbox.datasets.local import LocalDatasets
from serenata_toolbox.datasets.remote import RemoteDatasets


class Datasets:
    """
    This is a wrapper for three different classes together handles the datasets
    locally and remotelly.

    Inside the instantiated object there are three main objects: local, remote,
    and downloader:

    * `Datasets.local` handles listing all local datasets through the property
      `Datasets.local.all` and deleting local datasets with the method
      `Datasets.local.delete(filename)`;

    * `Datasets.remote` has the `Datasets.remote.all` property and
      `Dataset.remote.delete(filename)` method just like its local equivalent;
      in addition to them this object offers the
      `Datasets.remote.upload(file_path)` method to upload a local file to the
      remote bucket; `Datasets.remote` does not handles downloads because
      `boto3` does not support `asyncio` and we prefer to use async tasks to
      allow the download of more than one file in parallel;

    * `Datasets.downloader` implements a async manager to download files from
      the remote bucket. It's `Datasets.downloader.download(files)` take the
      path for a single file (str) as argument or an iterable of paths (str).

    Yet this wrapper implement the `Dataset.upload_all()` method to upload all
    local datasets that are not present in the remote bucket.
    """

    def __init__(self, local_directory=None):
        """
        :param local_directory: (str) path to local directory of the datasets
        """
        if not local_directory:
            local_directory = 'data'

        self.local = LocalDatasets(local_directory)
        self.remote = RemoteDatasets()
        self.downloader = Downloader(
            local_directory,
            bucket=self.remote.bucket,
            **self.remote.credentials
        )

    @property
    def pending(self):
        """Files that are in the local datasets but not in S3."""
        local = set(self.local.all)
        remote = set(self.remote.all)
        yield from (local - remote)

    def upload_all(self):
        for file_name in self.pending:
            full_path = os.path.join(self.local.directory, file_name)
            self.remote.upload(full_path)


# shortcuts & retrocompatibility

def fetch(filename, destination_path):
    datasets = Datasets(destination_path)
    return datasets.downloader.download(filename)

def fetch_latest_backup(destination_path):
    datasets = Datasets(destination_path)
    files = datasets.downloader.LATEST
    return datasets.downloader.download(files)

import os

from serenata_toolbox.datasets.downloader import Downloader
from serenata_toolbox.datasets.local import LocalDatasets
from serenata_toolbox.datasets.remote import RemoteDatasets


class Datasets:
    """
    This is a wrapper for three different classes that together handle the
    datasets (locally and remotelly).

    Datasets class takes one argument: the path to the local directory of the
    dataset files (e.g. data/ or /tmp/serenata-data). The argument is optional
    and the default value is data/ (following the default usage in the main
    repo, serenata-de-amor).

    The remote part of the class expect to find Amazon credentials in a
    config.ini file with an Amazon section (e.g. config.ini.exemple).

    Inside it object there are three main objects: local, remote, and
    downloader:

    * `Datasets.local` handles listing all local datasets through the property
      `Datasets.local.all` (hint: it's a generator) and deleting local datasets
      with the method `Datasets.local.delete(filename)`;

    * `Datasets.remote` has the `Datasets.remote.all` property (hint: it's also
      a generator) and `Dataset.remote.delete(filename)` method just like its
      local equivalent; in addition to them this object offers the
      `Datasets.remote.upload(file_path)` method to upload a local file to the
      remote bucket; `Datasets.remote` does not handles downloads because
      `boto3` does not support `asyncio` and we prefer to use async tasks to
      allow the download of more than one file in parallel;

    * `Datasets.downloader` implements a async manager to download files from
      the remote bucket. It's `Datasets.downloader.download(files)` take the
      path for a single file (str) as argument or an iterable of paths (str).

    Yet this wrapper implement the `Dataset.upload_all()` method to upload all
    local datasets that are not present in the remote bucket.

    :param local_directory: (str) path to local directory of the datasets
    """

    def __init__(self, local_directory=None):
        if not local_directory:
            local_directory = 'data'

        self.local = LocalDatasets(local_directory)
        self.remote = RemoteDatasets()
        self.downloader = Downloader(
            local_directory,
            bucket=self.remote.bucket,
            **self.remote.credentials
        )

    @property
    def pending(self):
        """Files that are in the local datasets but not in S3."""
        local = set(self.local.all)
        remote = set(self.remote.all)
        yield from (local - remote)

    def upload_all(self):
        for file_name in self.pending:
            full_path = os.path.join(self.local.directory, file_name)
            self.remote.upload(full_path)


# shortcuts & retrocompatibility

def fetch(filename, destination_path):
    datasets = Datasets(destination_path)
    return datasets.downloader.download(filename)

def fetch_latest_backup(destination_path):
    datasets = Datasets(destination_path)
    files = datasets.downloader.LATEST
    return datasets.downloader.download(files)

Enhance Datasets docstrings