from urllib.request import Request, urlopen
import sys
import os
import json
import re
import urllib.error
import urllib.request

# to import from a parent directory we need to add that directory to the system path
csd = os.path.dirname(
    os.path.realpath(__file__))  # get current script directory
parent = os.path.dirname(csd)  #  parent directory (should be the scrapers one)
sys.path.append(
    parent
)  # add parent dir to sys path so that we can import py_common from ther

try:
    import requests
    from requests.utils import requote_uri
    from requests.structures import CaseInsensitiveDict
except ModuleNotFoundError:
    print(
        "You need to install the requests module. (https://docs.python-requests.org/en/latest/user/install/)",
        file=sys.stderr)
    print(
        "If you have pip (normally installed with python), run this command in a terminal (cmd): pip install requests",
        file=sys.stderr)
    sys.exit()

try:
    from py_common import log
    import py_common.graphql as graphql
except ModuleNotFoundError:
    print(
        "You need to download the folder 'py_common' from the community repo! (CommunityScrapers/tree/master/scrapers/py_common)",
        file=sys.stderr)
    sys.exit()
import config

SHOKO_API_KEY = ''  #leave empty it gets your Shoko api key with your shoko server username and password
SHOKO_URL = config.SHOKO.get("url", "")
SHOKO_USER = config.SHOKO.get("user", "")
SHOKO_PASS = config.SHOKO.get("pass", "")



def validate_user_inputs() -> bool:
    shoko = bool(re.search(r"^(http|https)://.+:\d+$", SHOKO_URL))
    if shoko is False:
        log.error("Shoko Url needs to be hostname:port and is currently " +
                  SHOKO_URL)
    return (shoko)


def get_filename(scene_id: str) -> str:
    log.debug(f"stash sceneid: {scene_id}")
    log.debug(graphql.getScene(scene_id))
    data = graphql.getScene(scene_id)
    path = data['files'][0]['path']
    log.debug("scene path in stash: " + str(path))
    pattern = "(^.+)([\\\\]|[/])"
    replace = ""
    filename = re.sub(pattern, replace, str(path))
    log.debug(f"encoded filename: {filename}")
    return filename


def find_scene_id(scene_id: str) -> (str, str):
    if SHOKO_API_KEY == "":
        apikey = get_apikey()
    else:
        apikey = SHOKO_API_KEY
    filename = get_filename(scene_id)
    return filename, apikey


def lookup_scene(scene_id: str, epnumber: str, apikey: str, date: str) -> dict:
    log.debug(epnumber)
    title, details, cover, tags = get_series(apikey, scene_id)  #, characters
    tags = tags + ["ShokoAPI"] + ["Hentai"]
    #characters_json = json.dumps(characters)
    #json_object = json.loads(characters_json)
    #character = json_object[0]['character']
    #log.info(str(character))
    res = {}
    res['title'] = title + " 0" + epnumber
    res['details'] = details
    res['image'] = cover
    res['date'] = date
    res['tags'] = [{"name": i} for i in tags]
    log.debug("sceneinfo from Shoko: " + str(res))
    return res


def get_apikey() -> str:
    headers = CaseInsensitiveDict()
    headers["Content-Type"] = "application/json"

    values = '{"user": "' + SHOKO_USER + '","pass": "' + SHOKO_PASS + '","device": "Stash Scan"}'

    resp = requests.post(SHOKO_URL + '/api/auth', data=values, headers=headers)
    if resp.status_code == 200:
        log.debug("got Shoko's apikey: ")
        apikey = str(resp.json()['apikey'])
        return apikey
    elif resp.status_code == 401:
      log.error("check if your shoko server username/password is correct")
      return None
    else:
        log.error("response from Shoko was not successful stash resp_code: " + str(resp.status_code))
        return None


def find_scene(apikey: str, filename: str):
    headers = CaseInsensitiveDict()
    headers["apikey"] = apikey
    url_call = requote_uri(SHOKO_URL + '/api/ep/getbyfilename?filename=' + filename)
    log.debug(f"using url: {url_call}")
    request = Request(url_call, headers=headers)

    try:
        response_body = urlopen(request).read()
    except urllib.error.HTTPError as http_error:
        if http_error.code == 404:
            log.info(f"the file: {filename} is not matched on shoko")
    except urllib.error.URLError as url_error:
        # Not an HTTP-specific error (e.g. connection refused)
        # ...
        log.error(f'URLError: {url_error.reason}')
    else:
        # 200
        log.info(f"the file: {filename} is matched on shoko")
        json_object = json.loads(response_body.decode('utf-8'))
        log.debug("found scene\t" + str(json_object))
        scene_id = json_object['id']
        epnumber = str(json_object['epnumber']) + ' ' + str(json_object['name'])
        date = json_object['air']
        return scene_id, epnumber, date


def get_series(apikey: str, scene_id: str):
    headers = CaseInsensitiveDict()
    headers["apikey"] = apikey
    request = Request(SHOKO_URL + '/api/serie/fromep?id=' + scene_id, headers=headers)

    response_body = urlopen(request).read()
    json_object = json.loads(response_body.decode('utf-8'))
    log.debug("got series:\t" + str(json_object))
    title = json_object['name']
    details = json_object['summary']
    local_sizes = json_object['local_sizes']['Episodes']
    log.debug("number of episodes " + str(local_sizes))
    #characters = json_object['roles']
    cover = SHOKO_URL + json_object['art']['thumb'][0]['url']
    tags = json_object['tags']
    return title, details, cover, tags  #, characters


def query(fragment: dict) -> dict:
    if fragment['title'] == "":
        scene_id = fragment['id']
        query = """query findScene($scene_id:ID!){findScene(id:$scene_id){files{basename}}}"""
        variables = {'scene_id': scene_id}
        result = call_graphql(query, variables)
        basename = result['findScene']['files'][0]['basename']
    filename, apikey = find_scene_id(fragment['id'])
    try:
        findscene_scene_id, findscene_epnumber, find_date = find_scene(apikey, filename)
    except:
        return None
    scene_id = str(findscene_scene_id)
    epnumber = str(findscene_epnumber)
    date = str(find_date)
    apikey = str(apikey)
    log.debug(f"Found scene id: {scene_id}")
    result = lookup_scene(scene_id, epnumber, apikey, date)
    return result


def main():
    mode = sys.argv[1]
    fragment = json.loads(sys.stdin.read())
    log.debug(str(fragment))
    data = None
    check_input = validate_user_inputs()
    if check_input is True:
        if mode == 'query':
            data = query(fragment)
    print(json.dumps(data))

def call_graphql(query, variables=None):
    return graphql.callGraphQL(query, variables)


if __name__ == '__main__':
    main()