# JSON API classes

import brainspell
from article_helpers import *
from base_handler import *
from search_helpers import *
from user_account_helpers import *

# For GitHub OAuth
import requests
import urllib.parse
import os
import hashlib

import itertools

REQ_DESC = "The fields to search through. 'x' is experiments, 'p' is PMID, 'r' is reference, and 't' is title + authors + abstract."
START_DESC = "The offset of the articles to show; e.g., start = 10 would return results 11 - 20."
PUT = requests.put
GET = requests.get
POST = requests.post

assert "github_frontend_client_id" in os.environ \
    and "github_frontend_client_secret" in os.environ, \
    "You need to set the 'github_frontend_client_id' and 'github_frontend_client_secret' environment variables."

assert "github_frontend_dev_client_id" in os.environ \
    and "github_frontend_dev_client_secret" in os.environ, \
    "You need to set the 'github_frontend_dev_client_id' and 'github_frontend_dev_client_secret' environment variables."


class ListEndpointsEndpointHandler(BaseHandler):
    """ Return a list of all JSON API endpoints.
    Do not include /help pages, or aliases. """

    parameters = {}

    endpoint_type = Endpoint.PULL_API

    @staticmethod
    async def process(response, args):
        endpoints = brainspell.getJSONEndpoints()
        response["endpoints"] = [name for name, cls in endpoints if name[len(
            name) - 1:] != "/" and name[len(name) - 4:] != "help"]
        return response


# BEGIN: Authentication endpoints

class GithubOauthProductionEndpointHandler(BaseHandler):
    """ GitHub login authentication. Return the GitHub token and
    Brainspell API key. """

    parameters = {
        "code": {
            "type": str,
            "description": "The code returned after GitHub OAuth."
        }
    }

    endpoint_type = Endpoint.PULL_API

    client_id_key = "github_frontend_client_id"
    client_secret_key = "github_frontend_client_secret"

    async def process(self, response, args):
        code = args["code"]

        data = {
            "client_id": os.environ[self.client_id_key],
            "client_secret": os.environ[self.client_secret_key],
            "code": code
        }

        # TODO: Make asynchronous, since this is blocking.
        result = requests.post(
            "https://github.com:443/login/oauth/access_token",
            data
        )
        params = urllib.parse.parse_qs(result.text)

        try:
            response["github_token"] = params["access_token"][0]
            user = await self.github_request(GET, "user", params["access_token"][0])
            # idempotent operation to make sure GitHub user is in our
            # database
            register_github_user(user)
            hasher = hashlib.sha1()
            hasher.update(str(user["id"]).encode('utf-8'))
            api_key = hasher.hexdigest()
            response["api_key"] = api_key
        except BaseException:
            response["success"] = 0
            response["description"] = "Authentication failed."

        return response


class GithubOauthDevelopmentEndpointHandler(
        GithubOauthProductionEndpointHandler):
    """ Endpoint for development OAuth. """

    client_id_key = "github_frontend_dev_client_id"
    client_secret_key = "github_frontend_dev_client_secret"


# BEGIN: Collections v2 endpoints

class CreateCollectionEndpointHandler(BaseHandler):
    """ Create a repository and the necessary files for a new collection. """

    parameters = {
        "collection_name": {
            "type": str,
            "description": "The name of this collection, as seen and defined by the user."},
        "description": {
            "type": str},
        "inclusion_criteria": {
            "type": json.loads,
            "description": "A JSON-serialized list of inclusion criteria.",
            "default": "[]"},
        "exclusion_criteria": {
            "type": json.loads,
            "description": "A JSON-serialized list of exclusion criteria.",
            "default": "[]"},
        "tags": {
            "type": json.loads,
            "description": "JSON-serialized list of tags.",
            "default": "[]"},
        "github_token": {
            "type": str}}

    api_version = 2
    endpoint_type = Endpoint.PUSH_API

    def validate(self, j):
        # Validate a list of strings.
        if not isinstance(j, list):
            return False
        for s in j:
            if not isinstance(s, str):
                return False