import logging
import os

from bulk_update.helper import bulk_update
from datetime import datetime

from django.conf import settings
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import User
from django.contrib.sites.models import Site
from django.core.cache import cache
from django.core.paginator import Paginator, EmptyPage
from django.db import transaction
from django.db.models import Q
from django.http import (
    Http404,
    HttpResponse,
    HttpResponseBadRequest,
    HttpResponseForbidden,
    JsonResponse,
    StreamingHttpResponse
)
from django.shortcuts import get_object_or_404, render, redirect
from django.utils import timezone
from django.utils.datastructures import MultiValueDictKeyError
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import (
    condition,
    require_POST
)

from pontoon.base import forms
from pontoon.base import utils
from pontoon.base.models import (
    ChangedEntityLocale,
    Entity,
    Locale,
    Project,
    ProjectLocale,
    Resource,
    TranslationMemoryEntry,
    TranslatedResource,
    Translation,
    UserProfile,
)


log = logging.getLogger(__name__)


def home(request):
    """Home view."""

    user = request.user
    project = Project.objects.get(id=1)

    # Redirect user to the selected home page or '/'.
    if user.is_authenticated() and user.profile.custom_homepage != '':
        # If custom homepage not set yet, set it to the most contributed locale team page
        if user.profile.custom_homepage is None:
            if user.top_contributed_locale:
                user.profile.custom_homepage = user.top_contributed_locale
                user.profile.save(update_fields=['custom_homepage'])

        if user.profile.custom_homepage:
            return redirect('pontoon.teams.team', locale=user.profile.custom_homepage)

    locale = utils.get_project_locale_from_request(request, project.locales) or 'en-GB'
    path = Resource.objects.filter(
        project=project,
        translatedresources__locale__code=locale
    ).values_list('path', flat=True)[0]

    return translate(request, locale, project.slug, path)


def heroku_setup(request):
    """
    Heroku doesn't allow us to set SITE_URL or Site during the build phase of an app.
    Because of that we have to set everything up after build is done and app is
    able to retrieve a domain.
    """
    app_host = request.get_host()
    homepage_url = 'https://{}/'.format(app_host)
    site_domain = Site.objects.get(pk=1).domain

    if not os.environ.get('HEROKU_DEMO') or site_domain != 'example.com':
        return redirect(homepage_url)

    admin_email = os.environ.get('ADMIN_EMAIL')
    admin_password = os.environ.get('ADMIN_PASSWORD')

    User.objects.create_superuser(admin_email, admin_email, admin_password)
    Site.objects.filter(pk=1).update(name=app_host, domain=app_host)

    Project.objects.filter(slug='pontoon-intro').update(
        url='https://{}/intro/'.format(app_host)
    )

    # Clear the cache to ensure that SITE_URL will be regenerated.
    cache.delete(settings.APP_URL_KEY)
    return redirect(homepage_url)


# TRANSLATE VIEWs


def translate(request, locale, slug, part):
    """Translate view."""
    locale = get_object_or_404(Locale, code=locale)
    project = get_object_or_404(Project.objects.available(), slug=slug)

    if locale not in project.locales.all():
        raise Http404

    projects = (
        Project.objects.available()
        .prefetch_related('subpage_set')
        .order_by('name')
    )

    return render(request, 'translate.html', {
        'download_form': forms.DownloadFileForm(),
        'upload_form': forms.UploadFileForm(),
        'locale': locale,
        'locale_projects': locale.available_projects_list(),
        'locales': Locale.objects.available(),
        'part': part,
        'project': project,
        'projects': projects,
    })


@utils.require_AJAX
def locale_projects(request, locale):
    """Get active projects for locale."""
    locale = get_object_or_404(Locale, code=locale)

    return JsonResponse(locale.available_projects_list(), safe=False)


@utils.require_AJAX
def locale_project_parts(request, locale, slug):
    """Get locale-project pages/paths with stats."""
    locale = get_object_or_404(Locale, code=locale)
    project = get_object_or_404(Project, slug=slug)

    try:
        return JsonResponse(locale.parts_stats(project), safe=False)
    except ProjectLocale.DoesNotExist:
        raise Http404('Locale not enabled for selected project.')


@utils.require_AJAX
def authors_and_time_range(request, locale, slug, part):
    locale = get_object_or_404(Locale, code=locale)
    project = get_object_or_404(Project.objects.available(), slug=slug)
    paths = [part] if part != 'all-resources' else None

    translations = Translation.for_locale_project_paths(locale, project, paths)

    return JsonResponse({
        'authors': translations.authors().serialize(),
        'counts_per_minute': translations.counts_per_minute(),
    }, safe=False)


def _get_entities_list(locale, project, form):
    """Return a specific list of entities, as defined by the `entity_ids` field of the form.

    This is used for batch editing.
    """
    entities = (
        Entity.objects.filter(pk__in=form.cleaned_data['entity_ids'])
        .prefetch_resources_translations(locale)
        .distinct()
        .order_by('order')
    )

    return JsonResponse({
        'entities': Entity.map_entities(locale, entities),
        'stats': TranslatedResource.objects.stats(
            project, form.cleaned_data['paths'], locale
        ),
    }, safe=False)


def _get_all_entities(locale, project, form, entities):
    """Return entities without pagination.

    This is used by the in-context mode of the Translate page.
    """
    has_next = False
    entities_to_map = Entity.for_project_locale(
        project,
        locale,
        paths=form.cleaned_data['paths'],
        exclude_entities=form.cleaned_data['exclude_entities']
    )
    visible_entities = entities.values_list('pk', flat=True)

    return JsonResponse({
        'entities': Entity.map_entities(locale, entities_to_map, visible_entities),
        'has_next': has_next,
        'stats': TranslatedResource.objects.stats(
            project, form.cleaned_data['paths'], locale
        ),
    }, safe=False)


def _get_paginated_entities(locale, project, form, entities):
    """Return a paginated list of entities.

    This is used by the regular mode of the Translate page.
    """
    paginator = Paginator(entities, form.cleaned_data['limit'])

    try:
        entities_page = paginator.page(1)
    except EmptyPage:
        return JsonResponse({
            'has_next': False,
            'stats': {},
            'authors': [],
            'counts_per_minute': [],
        })

    has_next = entities_page.has_next()
    entities_to_map = entities_page.object_list

    # If requested entity not on the first page
    if form.cleaned_data['entity']:
        entity_pk = form.cleaned_data['entity']

        # TODO: entities_to_map.values_list() doesn't return entities from selected page
        if entity_pk not in [e.pk for e in entities_to_map]:
            if entity_pk in entities.values_list('pk', flat=True):
                entities_to_map = list(entities_to_map) + list(entities.filter(pk=entity_pk))

    return JsonResponse({
        'entities': Entity.map_entities(locale, entities_to_map, []),
        'has_next': has_next,
        'stats': TranslatedResource.objects.stats(
            project, form.cleaned_data['paths'], locale