# -*- coding: utf-8 -*-
"""
.. See the NOTICE file distributed with this work for additional information
   regarding copyright ownership.
   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at
       http://www.apache.org/licenses/LICENSE-2.0
   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
"""
import inspect
import logging

from coreapi import Client

from ebi.ols.api.base import ListClientMixin, DetailClientMixin, HALCodec, SearchClientMixin, retry_requests
from ebi.ols.api.helpers import OLSHelper, Property, Individual, Ontology, Term

def_page_size = 500
logger = logging.getLogger(__name__)


class OlsClient(object):
    """
    Official EMBL/EBI Ontology Lookup Service generic client.
    """
    site = 'https://www.ebi.ac.uk/ols/api'
    page_size = 500

    class ItemClient(object):

        def __init__(self, base_site):
            self.uri = base_site

        def __call__(self, *args, **kwargs):
            item = None
            if len(args) == 1:
                # consider only one args is the requested helper initialized
                item = args[0]
            if 'item' in kwargs:
                item = kwargs.get('item')
            if item:
                if not issubclass(item.__class__, OLSHelper):
                    raise NotImplementedError('Unable to fin any suitable client for %s', item.__class__.__name__)
                base_uri = 'ontologies/{}'.format(item.ontology_name) if item.ontology_name or kwargs.get(
                    'ontology_name',
                    False) else None
                uri = '/'.join(filter(None, [self.uri, base_uri, item.path]))
                logger.debug('ItemClient uri %s', uri)
                inner_client = DetailClientMixin(uri, item.__class__)
                return inner_client(item.iri)
            else:
                assert ('ontology_name' in kwargs)
                assert ('iri' in kwargs)
                assert ('type' in kwargs)
                item = kwargs.get('type')
                if inspect.isclass(item):
                    assert (issubclass(item, OLSHelper))
                else:
                    assert (issubclass(item.__class__, OLSHelper))
                return self.__call__(item=item(ontology_name=kwargs.get('ontology_name'), iri=kwargs.get('iri')))

    @retry_requests
    def __init__(self, page_size=None, base_site=None):
        # Init client from base Api URI
        # Hacky page size update for all future request to OlsClient
        OlsClient.page_size = page_size or def_page_size
        if base_site:
            OlsClient.site = base_site
        document = Client(decoders=[HALCodec()]).get(self.site)
        logger.debug('OlsClient [%s][%s]', document.url, self.page_size)
        # List Clients
        self.ontologies = ListClientMixin('/'.join([self.site, 'ontologies']), Ontology, document,
                                          self.page_size)
        self.terms = ListClientMixin('/'.join([self.site, 'terms']), Term, document, self.page_size)
        self.properties = ListClientMixin('/'.join([self.site, 'properties']), Property, document,
                                          self.page_size)
        self.individuals = ListClientMixin('/'.join([self.site, 'individuals']), Individual, document,
                                           self.page_size)
        # Details client
        self.ontology = DetailClientMixin('/'.join([self.site, 'ontologies']), Ontology)
        self.term = DetailClientMixin('/'.join([self.site, 'terms']), Term)
        self.property = DetailClientMixin('/'.join([self.site, 'properties']), Property)
        self.individual = DetailClientMixin('/'.join([self.site, 'individuals']), Individual)
        # Special clients
        self.search = SearchClientMixin('/'.join([self.site, 'search']), OLSHelper, document, self.page_size)
        self.detail = self.ItemClient(self.site)
