from pydantic import BaseModel, Schema
from typing import Dict, List
from datetime import datetime
from fastapi import HTTPException
import logging
from time import time

rels = dict(issupplementto="IsSupplementTo", issupplementedby="IsSupplementedBy", references="References",
            isreferencedby="IsReferencedBy")


pid_resolver = {
    "pdb": "http://www.rcsb.org/pdb/explore/explore.do?structureId=%s",
    "ncbi-n": "http://www.ncbi.nlm.nih.gov/gquery/?term=%s",
    "ncbi": "http://www.ncbi.nlm.nih.gov/gquery/?term=%s",
    "pmid": "http://www.ncbi.nlm.nih.gov/pubmed/%s",
    "pmcid": "http://www.ncbi.nlm.nih.gov/pmc/articles/%s",
    "pubmedid": "http://www.ncbi.nlm.nih.gov/pubmed/%s",
    "doi": "http://dx.doi.org/%s",
    "genbank": "http://www.ncbi.nlm.nih.gov/nucest/%s?report=genbank",
    "nuccore": "http://www.ncbi.nlm.nih.gov/nucest/%s?report=genbank",
    "swiss-prot": "http://www.ncbi.nlm.nih.gov/nucest/%s?report=genbank",
    "arrayexpress": "http://www.ncbi.nlm.nih.gov/nucest/%s?report=genbank",
    "biomodels": "http://www.ncbi.nlm.nih.gov/nucest/%s?report=genbank",
    "bmrb": "http://www.ncbi.nlm.nih.gov/nucest/%s?report=genbank",
    "ena": "http://www.ncbi.nlm.nih.gov/nucest/%s?report=genbank",
    "geo": "http://www.ncbi.nlm.nih.gov/nucest/%s?report=genbank",
    "ensembl": "http://www.ncbi.nlm.nih.gov/nucest/%s?report=genbank",
    "mgi": "http://www.ncbi.nlm.nih.gov/nucest/%s?report=genbank",
    "bind": "http://www.ncbi.nlm.nih.gov/nucest/%s?report=genbank",
    "pride": "http://www.ncbi.nlm.nih.gov/nucest/%s?report=genbank",
    "ddbj": "http://www.ncbi.nlm.nih.gov/nucest/%s?report=genbank",
    "bioproject": "http://www.ncbi.nlm.nih.gov/nucest/%s?report=genbank",
    "embl": "http://www.ncbi.nlm.nih.gov/nucest/%s?report=genbank",
    "sra": "http://www.ncbi.nlm.nih.gov/nucest/%s?report=genbank",
    "url":"%s"
}


def resolveIdentifier(pid, pid_type):
    if pid_type != None:
        if pid_type.lower() in pid_resolver:
            return pid_resolver[pid_type.lower()] % pid
        else:
            return "http://identifiers.org/%s:%s" % (pid_type, pid)


class LinkProvider(BaseModel):
    name:str = Schema(None, title= "The name of the Provider that provides the links", max_length= 300)
    totalRelationships:int=Schema(None, title= "The number of links that It provides")

class LinkPublisher(BaseModel):
    name:str = Schema(None, title= "The name of the Publisher that provides the links", max_length= 300)
    totalRelationships:int=Schema(None, title= "The number of links that It provides")


class IdentifierType(BaseModel):
    ID: str = None
    IDScheme:str = None
    IDURL:str= None

class ScholixProviderType(BaseModel):
    name:str = None
    identifier:List[IdentifierType] = []

class RelationshipType(BaseModel):
    Name:str
    SubType:str = None
    SubTypeSchema:str = None

class CreatorType(BaseModel):
    Name: str
    Identifier:List[IdentifierType] = []
    


class ScholixItemType(BaseModel):
    Identifier:List[IdentifierType] = []
    Title:str = None
    Type:str 
    Creator:List[CreatorType] = []
    PublicationDate:str = None
    Publisher:List[ScholixProviderType] =[]    

class ScholixType(BaseModel):
    HarvestDate:str=None
    LicenseURL:str=None
    LinkProvider:List[ScholixProviderType] =[]
    LinkPublicationDate: str = None
    RelationshipType:RelationshipType
    source:ScholixItemType
    target:ScholixItemType
    

class PageResultType(BaseModel):
    currentPage:int
    totalLinks:int
    totalPages:int
    result:List[ScholixType] = []


def get_scholix_resource(item):
    title = ''
    if 'title' in item:
        title = item.title
    if title is not None and len(title):
        if title[0] == '"' and title[-1] == '"':
            title = title[1:-1]
    identifier = [dict(ID=x.identifier, IDScheme=x.schema, IDURL=x.url) for x in
                  item.identifier]
    identifier.append(dict(ID=item.dnetIdentifier, IDScheme='D-Net Identifier', IDURL='http://scholexplorer.openaire.eu/index.html#/detail/%s'%item.dnetIdentifier))
    creator = []
    if 'creator' in item and item.creator is not None:        
        creator = [dict(Name=x.name) for x in item.creator]
    publicationDate = None
    if 'publicationDate' in item:
        publicationDate = item.publicationDate
    publisher = []
    if 'publisher' in item and item.publisher is not None:
        publisher = [dict(name= x.name) for x in item.publisher if x.name is not None]
    c_type = item.objectType
    if item.objectType == 'publication':
        c_type = 'literature'

    resource = dict(Title=title, Identifier=identifier, Creator=creator, PublicationDate= publicationDate, Publisher = publisher, Type= c_type)

    return resource


def convert_response(response):
    now = datetime.now()
    log = logging.getLogger("scholexplorer")
    start = time()
    for item in response.hits:
        current_item = {'LinkPublicationDate': item.publicationDate, 'HarvestDate': item.publicationDate,
                         "LinkProvider": []}
        for linkProvider in item.linkprovider:
            current_item['LinkProvider'].append(ScholixProviderType(name=linkProvider.name,
                                                     identifier=[IdentifierType(ID=x.identifier, IDScheme=x.schema) for x in
                                                                 linkProvider.identifiers]))

        rel_sub_type = rels.get(item.relationship.name.lower(), "IsRelatedTo")
        current_item['RelationshipType'] = dict(Name=rel_sub_type, SubType=item.relationship.name,
                                                SubTypeSchema=item.relationship.schema)

        current_item['source'] = get_scholix_resource(item.source)
        current_item['target'] = get_scholix_resource(item.target)

        yield current_item
    end = time()
    log.debug("response converted in {} ms".format(end-start))

def create_response(response, current_page):
    log = logging.getLogger("scholexplorer")    
    if current_page > 9999:
        raise HTTPException(status_code=400,detail="MAX NUMBER OF PAGE REACHED")

    start = time()

    
    result = {'totalLinks': response.hits.total.value, 'currentPage': current_page /100,
              'totalPages': 1 + response.hits.total.value / 100, 'result': []}
    result['result'] = convert_response(response)
    end = time()

    log.debug("response created in {} ms".format(end-start))
    return result