# -*- coding: utf-8 -*-

"""Conversion functions for BEL graphs with GraphDati.

Note that these are not exact I/O - you can't currently use them as a round trip because
the input functions expect the GraphDati format that's output by BioDati.
"""

import gzip
import json
import logging
from collections import defaultdict
from typing import Any, Iterable, List, Mapping, Optional, TextIO, Tuple, Union

import pyparsing
from networkx.utils import open_file
from tqdm.autonotebook import tqdm

from .jgif import NAMESPACE_TO_PATTERN
from ..canonicalize import edge_to_tuple
from ..constants import (
    ANNOTATIONS,
    CITATION,
    CITATION_TYPE_PUBMED,
    CITATION_TYPE_URL,
    EVIDENCE,
    IDENTIFIER,
    NAMESPACE,
    RELATION,
    UNQUALIFIED_EDGES,
)
from ..parser import BELParser
from ..struct import BELGraph
from ..typing import EdgeData

__all__ = [
    "to_graphdati",
    "from_graphdati",
    "to_graphdati_file",
    "from_graphdati_file",
    "to_graphdati_gz",
    "from_graphdati_gz",
    "to_graphdati_jsons",
    "from_graphdati_jsons",
    "to_graphdati_jsonl",
    "to_graphdati_jsonl_gz",
]

logger = logging.getLogger(__name__)

NanopubMapping = Mapping[str, Mapping[str, Any]]

SCHEMA_URI = "https://github.com/belbio/schemas/blob/master/schemas/nanopub_bel-1.0.0.yaml"
GRAPHDATI_PUBLICATION_TYPES = {
    "PMID": CITATION_TYPE_PUBMED,
    "http": CITATION_TYPE_URL,
    "https": CITATION_TYPE_URL,
}


@open_file(1, mode="w")
def to_graphdati_file(graph: BELGraph, path: Union[str, TextIO], use_identifiers: bool = True, **kwargs) -> None:
    """Write this graph as GraphDati JSON to a file.

    :param graph: A BEL graph
    :param path: A path or file-like
    """
    json.dump(to_graphdati(graph, use_identifiers=use_identifiers), path, ensure_ascii=False, **kwargs)


def from_graphdati_file(path: Union[str, TextIO]) -> BELGraph:
    """Load a file containing GraphDati JSON.

    :param path: A path or file-like
    """
    return from_graphdati(json.load(path))


def to_graphdati_gz(graph: BELGraph, path: str, **kwargs) -> None:
    """Write a graph as GraphDati JSON to a gzip file."""
    with gzip.open(path, "wt") as file:
        to_graphdati_file(graph, file, **kwargs)


def from_graphdati_gz(path: str) -> BELGraph:
    """Read a graph as GraphDati JSON from a gzip file."""
    with gzip.open(path, "rt") as file:
        return from_graphdati(json.load(file))


def to_graphdati_jsons(graph: BELGraph, **kwargs) -> str:
    """Dump this graph as a GraphDati JSON object to a string.

    :param graph: A BEL graph
    """
    return json.dumps(to_graphdati(graph), ensure_ascii=False, **kwargs)


def from_graphdati_jsons(s: str) -> BELGraph:
    """Load a graph from a GraphDati JSON string.

    :param graph: A BEL graph
    """
    return from_graphdati(json.loads(s))


@open_file(1, mode="w")
def to_graphdati_jsonl(graph, file, use_identifiers: bool = True, use_tqdm: bool = True):
    """Write this graph as a GraphDati JSON lines file.

    :param graph: A BEL graph
    """
    for nanopub in _iter_graphdati(graph, use_identifiers=use_identifiers, use_tqdm=use_tqdm):
        print(json.dumps(nanopub), file=file)


def to_graphdati_jsonl_gz(graph: BELGraph, path: str, **kwargs) -> None:
    """Write a graph as GraphDati JSONL to a gzip file.

    :param graph: A BEL graph
    """
    with gzip.open(path, "wt") as file:
        to_graphdati_jsonl(graph, file, **kwargs)


def to_graphdati(
    graph,
    *,
    use_identifiers: bool = True,
    skip_unqualified: bool = True,
    use_tqdm: bool = False,
    metadata_extras: Optional[Mapping[str, Any]] = None,
) -> List[NanopubMapping]: