from boar.articles.models import Section, Article, Tag
from boar.common.views import BaseView
from django.contrib.auth.models import User
from django.http import Http404
from django.utils.datastructures import SortedDict
from haystack.forms import SearchForm
from haystack.query import SearchQuerySet, EmptySearchQuerySet
 
class BaseSearchView(BaseView):
    template = 'search/search.html'
 
    def __init__(self, template=None, load_all=True, form_class=SearchForm, searchqueryset=None):
        super(BaseSearchView, self).__init__()
 
        if searchqueryset is None:
            searchqueryset = SearchQuerySet()
 
        self.load_all = load_all
        self.form_class = form_class
        self.searchqueryset = searchqueryset
 
        if template is not None:
            self.template = template
 
    def get_context(self, request):        
        form = self.build_form(request)
        query = self.get_query(request, form)
        results = self.get_results(request, form, query)
 
        context = super(BaseSearchView, self).get_context(request)
        context.update({
            'form': form,
            'query': query,
            'results': results,
            'facets': self.get_facets(request, results),
        })
        context.update(self.get_extra_context(request, form))
        return context
 
    def get_extra_context(self, request, form):
        return {}
 
    def build_form(self, request):
        """
        Instantiates the form the class should use to process the search query.
        """
        if self.searchqueryset is None:
            return self.form_class(request.GET, load_all=self.load_all)
 
        return self.form_class(request.GET, searchqueryset=self.searchqueryset, load_all=self.load_all)
 
    def get_query(self, request, form):
        """
        Returns the query provided by the user.
 
        Returns an empty string if the query is invalid.
        """
        if form.is_valid():
            return form.cleaned_data['q']
 
        return ''
 
    def get_results(self, request, form, query):
        """
        Fetches the results via the form.
 
        Returns an empty list if there's no query to search with.
        """
        if query:
            return form.search()
 
        return EmptySearchQuerySet()
 
    def get_facets(self, request, results):
        return results.facet_counts()
 
 
class SearchView(BaseSearchView):
    pub_date_facets = SortedDict([
        ('[NOW-7DAYS TO NOW]', 'Past week'),
        ('[NOW-1MONTH TO NOW]', 'Past month'),
        ('[NOW-1YEAR TO NOW]', 'Past year'),
    ])
 
    def __init__(self, *args, **kwargs):
        kwargs['searchqueryset'] = SearchQuerySet().facet('section').facet('tag')
        for key in self.pub_date_facets:
            kwargs['searchqueryset'] = kwargs['searchqueryset'].query_facet('pub_date', key)
        super(SearchView, self).__init__(*args, **kwargs)
 
    def get_extra_context(self, request, form):
        if form.cleaned_data['q']:
            users = SearchQuerySet().models(User).load_all().auto_query(
                form.cleaned_data['q']
            )
        else:
            users = EmptySearchQuerySet()
        return {
            'user_results': users,
        }
 
    def get_results(self, request, form, query):
        if query and form.is_valid():
            sqs = self.searchqueryset.auto_query(
                    form.cleaned_data['q']).models(Article).load_all()
            for facet in ('section', 'tag', 'pub_date'):
                key = 'facet_%s' % facet
                if key in request.GET and request.GET[key]:
                    sqs = sqs.narrow('%s:%s' % (facet, request.GET[key]))
            return sqs
        return EmptySearchQuerySet()
 
    def get_facets(self, request, results):
        # FIXME: UURURRGGGHHH
        facet_counts = results.facet_counts()
        if not facet_counts:
            raise Http404('Invalid search, no facets reported.')
        facets = {'selected': {}}
        # pub_date
        facets['fields'] = {'pub_date': []}
        for key, name in self.pub_date_facets.items():
            facets['fields']['pub_date'].append({
                'name': name,
                'key': key,
                'count': facet_counts['queries'].get('pub_date_exact:%s' % key, 0),
            })
        pub_date = request.GET.get('facet_pub_date', None)
        if pub_date and pub_date in self.pub_date_facets:
            facets['selected']['pub_date'] = self.pub_date_facets[pub_date]
 
        # section
        sections = dict((o.slug, o) for o in Section.objects.all())
        facets['fields']['section'] = []
        for key, count in facet_counts['fields'].get('section', []):
            if count > 0:
                facets['fields']['section'].append({
                    'name': sections.get(key, key),
                    'key': key,
                    'count': count,
                })
        section = request.GET.get('facet_section', None)
        if section and section in sections:
            facets['selected']['section'] = sections[section]
 
        # tag
        tag_slugs = []
        facets['fields']['tag'] = []
        for key, count in facet_counts['fields'].get('tag', []):
            if count > 0:
                facets['fields']['tag'].append({
                    'key': key,
                    'name': key,
                    'count': count,
                })
                tag_slugs.append(key)
        tags = dict((t.slug, t) for t in Tag.objects.filter(slug__in=tag_slugs))
        for facet in facets['fields'].get('tag', []):
            try:
                facet['name'] = tags[facet['key']].name
            except KeyError:
                pass
        tag = request.GET.get('facet_tag', None)
        if tag and tag in tags:
            facets['selected']['tag'] = tags[tag]
 
        return facets