from __future__ import annotations
import typing as ty
import attrs
from arcana.core import PACKAGE_NAME, __version__, CODE_URL
from arcana.core.utils.misc import fromdict_converter


class Metadata:
    pass


@attrs.define
class ContainerMetadata(Metadata):

    type: ty.Optional[str] = None
    tag: ty.Optional[str] = None
    uri: ty.Optional[str] = None


@attrs.define
class GeneratorMetadata(Metadata):

    name: str = PACKAGE_NAME
    version: str = __version__
    description: str = f"Empty dataset created by {PACKAGE_NAME}"
    code_url: str = CODE_URL
    container: ContainerMetadata = attrs.field(
        default=None, converter=fromdict_converter(ContainerMetadata)
    )


@attrs.define
class SourceDatasetMetadata(Metadata):

    url: ty.Optional[str] = None
    doi: ty.Optional[str] = None
    version: ty.Optional[str] = None


DEFAULT_README = f"""
This dataset was specified/generated using the Arcana analysis workflows framework
{CODE_URL}. However, no specific README was provided so this template is used instead.

The dataset could have been defined on already existing data, using

    $ arcana dataset ...

or via the Python API
"""


@attrs.define(kw_only=True)
class DatasetMetadata(Metadata):
    """Metadata describing the dataset. Based on the Brain Imaging Data Structure (BIDS)
    specification for dataset metadata

    Parameters
    ----------
    name : str
        human interpretable name/title of the dataset
    generated_by : list[GeneratorMetadata]
        list of tools used to generate the dataset in its current form
    acknowledgements : str
        Acknowledgements of non-author contributions to the dataset
    authors : list[str]
        list of authors who contributed to the preparation of the dataset
    doi : str, optional
        the DOI for the dataset
    funding : list[str]
        acknowledgements of funding bodies) associated with the dataset
    license : str
        usage license for the dataset
    references : list[str]
        publications associated with the dataset
    how_to_acknowledge : str
        details on how to acknowledge the dataset in publications
    ethics_approvals : list[str]
        list of ethic approvals associated with the dataset
    sources : list[SourceDatasetMetadata]
        for derivative datasets, a list of source dataset used to generate the derivative
    description : str
        a description of the dataset
    type : str
        type of dataset, by default "derivative"
    row_metadata : dict[str, ty.Dict[str, str]]
        a dictionary of dictionaries that map keys of metadata present in the rows of the
        dataset with a short description. The key of the outer dictionary is the frequency
        of the rows
    """

    name: str = attrs.field(default="Autogenerated-dataset")
    generated_by: ty.List[GeneratorMetadata] = attrs.field(
        converter=fromdict_converter(ty.List[GeneratorMetadata])
    )
    acknowledgements: str = attrs.field(default="Generic BIDS dataset", repr=False)
    authors: ty.List[str] = attrs.field(factory=list, repr=False)
    doi: str = attrs.field(default=None, repr=False)
    funding: ty.List[str] = attrs.field(factory=list, repr=False)
    license: str = attrs.field(default="CC0", repr=False)
    references: ty.List[str] = attrs.field(factory=list)
    how_to_acknowledge: str = attrs.field(default="see licence")
    ethics_approvals: ty.List[str] = attrs.field(factory=list)
    sources: ty.List[SourceDatasetMetadata] = attrs.field(
        factory=list, converter=fromdict_converter(ty.List[SourceDatasetMetadata])
    )
    description: str = attrs.field(default=DEFAULT_README)
    type: str = attrs.field(default="derivative", repr=False)
    row_metadata: ty.Dict[str, ty.Dict[str, str]] = attrs.field(factory=dict)

    @generated_by.default
    def generated_by_default(self):
        return [GeneratorMetadata()]

    # def tobids(self):
    #     dct = {}
    #     dct["Name"] = self.name
    #     dct["Acknowledgements"] = self.acknowledgements
    #     dct["Authors"] = self.authors
    #     if self.doi:
    #         dct["DOI"] = self.doi
    #     dct["Funding"] = self.funding
    #     dct["License"] = self.license
    #     dct["References"] = self.references
    #     dct["HowToAcknowledge"] = self.how_to_acknowledge
    #     dct["EthicsApprovals"] = self.ethics_approvals
    #     dct["Readme"] = self.description
    #     dct["GeneratedBy"] = [gb.tobids() for gb in self.generated_by]
    #     dct["Sources"] = [s.tobids() for s in self.sources]
    #     return dct

    # @classmethod
    # def frombids(cls, dct):
    #     return cls(
    #         name=dct.get("Name"),
    #         acknowledgements=dct.get("Acknowledgements"),
    #         authors=dct.get("Authors"),
    #         doi=dct.get("DOI"),
    #         funding=dct.get("Funding"),
    #         license=dct.get("License"),
    #         references=dct.get("References"),
    #         how_to_acknowledge=dct.get("HowToAcknowledge"),
    #         ethics_approvals=dct.get("EthicsApprovals"),
    #         description=dct.get("Readme"),
    #         generated_by=[GeneratorMetadata(gb) for gb in dct["GeneratedBy"]],
    #         sources=[SourceDatasetMetadata(s) for s in dct["Sources"]],
    #     )


def metadata_converter(metadata):
    if not metadata:
        metadata = {}
    elif not isinstance(metadata, DatasetMetadata):
        metadata = DatasetMetadata(**metadata)
    return metadata
