from django.urls import NoReverseMatch
from rest_framework.reverse import reverse


def link_wrap(view, view_names):
    def wrapper(self, request, *args, **kwargs):
        """ wrapper function that inserts HTTP links on view """
        links = []
        for name in view_names:
            try:
                url = reverse(name, request=self.request)
            except NoReverseMatch:
                url = reverse(name, args, kwargs, request=request)
            links.append('<%s>; rel="%s"' % (url, name))
        response = view(self, request, *args, **kwargs)
        response['Link'] = ', '.join(links)
        return response
    for attr in dir(view):
        try:
            setattr(wrapper, attr, getattr(view, attr))
        except:
            pass
    return wrapper


def insert_links(viewset, basename):
    collection_links = ['api-root', '%s-list' % basename]
    object_links = ['api-root', '%s-list' % basename, '%s-detail' % basename]
    exception_links = ['api-root']
    list_links = ['api-root']
    retrieve_links = ['api-root', '%s-list' % basename]
    # Determine any `@action` or `@link` decorated methods on the viewset
    for methodname in dir(viewset):
        method = getattr(viewset, methodname)
        view_name = '%s-%s' % (basename, methodname.replace('_', '-'))
        if hasattr(method, 'collection_bind_to_methods'):
            list_links.append(view_name)
            retrieve_links.append(view_name)
            setattr(viewset, methodname, link_wrap(method, collection_links))
        elif hasattr(method, 'bind_to_methods'):
            retrieve_links.append(view_name)
            setattr(viewset, methodname, link_wrap(method, object_links))
    viewset.handle_exception = link_wrap(viewset.handle_exception, exception_links)
    viewset.list = link_wrap(viewset.list, list_links)
    viewset.retrieve = link_wrap(viewset.retrieve, retrieve_links)