import json
import os
import sys

import pandas as pd
import requests


class Client:
    """ Holds your NeuPrint credentials and does the data fetching.

    Parameters
    ----------
    server :        str
                    URL of server.
    token :         str, optional
                    NeuPrint token. Either pass explitily as an argument or set
                    as NEUPRINT_APPLICATION_CREDENTIALS environment variable.
                    Your token can be retrieved by clicking on your account in
                    the NeuPrint web interface.
    set_global :    bool, optional
                    If True (default), will make this client global so that
                    you don't have to explicitly pass it to each function.
    """

    def __init__(self, server, token=None, set_global=True):
        if token is None:
            token = os.environ.get('NEUPRINT_APPLICATION_CREDENTIALS')

        if token is None:
            raise RuntimeError("No token provided. Please provide one or set NEUPRINT_APPLICATION_CREDENTIALS")

        if ':' in token:
            try:
                token = json.loads(token)['token']
            except Exception:
                raise RuntimeError("Did not understand token. Please provide the entire JSON document or (only) the complete token string")

        token = token.replace('"', '')

        if '://' not in server:
            server = 'https://' + server
        elif server.startswith('http://'):
            raise RuntimeError("Server must be https, not http")
        elif not server.startswith('https://'):
            raise RuntimeError("Unknown protocol: {}".format(server.split('://')[0]))

        self.server = server
        self.session = requests.Session()
        self.session.headers.update({ "Authorization": "Bearer " + token,
                                      "Content-type": "application/json"} )

        if set_global:
            self.make_global()

    def make_global(self):
        """Sets this variable as global by attaching it as sys.module"""
        sys.modules['NEUPRINT_CLIENT'] = self

    def _fetch_raw(self, url, json=None):
        r = self.session.get(url, json=json)
        r.raise_for_status()
        return r.content

    def _fetch_json(self, url, json=None):
        r = self.session.get(url, json=json)
        r.raise_for_status()
        return r.json()

    def fetch_help(self):
        return self._fetch_raw("{}/api/help".format(self.server))

    def fetch_version(self):
        return self._fetch_json("{}/api/version".format(self.server))

    def fetch_available(self):
        return self._fetch_json("{}/api/available".format(self.server))

    def fetch_database(self):
        """ Fetch available datasets.
        """
        return self._fetch_json("{}/api/dbmeta/database".format(self.server))

    def fetch_datasets(self):
        """ Fetch available datasets.
        """
        return self._fetch_json("{}/api/dbmeta/datasets".format(self.server))

    def fetch_custom(self, cypher, format='pandas'):
        """ Fetch custom cypher.
        """
        assert format in ('json', 'pandas')
        try:
            result = self._fetch_json("{}/api/custom/custom".format(self.server),
                                      json={"cypher": cypher})
        except Exception:
            print('Error fetching cypher:')
            print(cypher)
            raise

        if format == 'json':
            return result

        df = pd.DataFrame(result['data'], columns=result['columns'])
        return df


@@ -1777,17 +1777,16 @@
 update(%7B
- 
 %22Authori
@@ -1850,17 +1850,16 @@
         
- 
 %22Content
@@ -1889,10 +1889,38 @@
 on%22%7D
- 
 )
+%0A        self.verbose = False
 %0A%0A  
@@ -2133,20 +2133,16 @@
 f _fetch
-_raw
 (self, u
@@ -2149,32 +2149,137 @@
 rl, json=None):%0A
+        if self.verbose:%0A            print('url:', url)%0A            print('cypher:', json.get('cypher'))%0A
         r = self
@@ -2356,16 +2356,8 @@
 rn r
-.content
 %0A%0A  
@@ -2369,20 +2369,19 @@
  _fetch_
-json
+raw
 (self, u
@@ -2405,35 +2405,33 @@
        r
- =
+eturn
  self.
-session.get
+_fetch
 (url, js
@@ -2442,54 +2442,103 @@
 son)
-%0A        r.raise_for_status()%0A        return r
+.content%0A%0A    def _fetch_json(self, url, json=None):%0A        return self._fetch(url, json=json)
 .jso
@@ -3715,9 +3715,8 @@
 turn df%0A
-%0A

add verbose parameter to client