from django.core.exceptions import ObjectDoesNotExist
from django.db import transaction
from django.shortcuts import redirect
from django.utils.translation.trans_real import to_language

import commonware.log
import jingo
import waffle
from waffle.decorators import waffle_switch

import amo
from amo.decorators import login_required
from amo.urlresolvers import reverse
from addons.models import Addon, AddonUser
from files.models import Platform
from users.models import UserProfile

import mkt
from mkt.constants import DEVICE_LOOKUP
from mkt.developers import tasks
from mkt.developers.decorators import dev_required
from mkt.developers.forms import AppFormMedia, CategoryForm, PreviewFormSet
from mkt.submit.forms import AppDetailsBasicForm
from mkt.submit.models import AppSubmissionChecklist
from mkt.themes.forms import NewThemeForm
from mkt.webapps.models import AddonExcludedRegion

from . import forms
from .decorators import read_dev_agreement_required, submit_step


log = commonware.log.getLogger('z.submit')


def submit(request):
    """Determine which step to redirect user to."""
    if not request.user.is_authenticated():
        return proceed(request)
    # If dev has already agreed, continue to next step.
    user = UserProfile.objects.get(pk=request.user.id)
    if user.read_dev_agreement:
        return redirect('submit.app.manifest')
    else:
        return redirect('submit.app.terms')


def proceed(request):
    """
    This is a fake "Terms" view that we overlay the login.
    We link here from the Developer Hub landing page.
    """
    if request.user.is_authenticated():
        return submit(request)
    agreement_form = forms.DevAgreementForm({'read_dev_agreement': True},
                                            instance=None)
    return jingo.render(request, 'submit/terms.html', {
        'step': 'terms',
        'agreement_form': agreement_form,
        'proceed': True,
    })


@login_required
@submit_step('terms')
def terms(request):
    # If dev has already agreed, continue to next step.
    if (getattr(request, 'amo_user', None) and
            request.amo_user.read_dev_agreement):
        return redirect('submit.app.manifest')

    agreement_form = forms.DevAgreementForm(
        request.POST or {'read_dev_agreement': True},
        instance=request.amo_user)
    if request.POST and agreement_form.is_valid():
        agreement_form.save()
        return redirect('submit.app.manifest')
    return jingo.render(request, 'submit/terms.html', {
        'step': 'terms',
        'agreement_form': agreement_form,
    })


@login_required
@read_dev_agreement_required
@submit_step('manifest')
@transaction.commit_on_success
def manifest(request):
    form = forms.NewWebappForm(request.POST or None)

    if request.method == 'POST' and form.is_valid():
        addon = Addon.from_upload(
            form.cleaned_data['upload'],
            [Platform.objects.get(id=amo.PLATFORM_ALL.id)],
            is_packaged=form.is_packaged())

        # Set the device type.
        for device in form.get_devices():
            addon.addondevicetype_set.get_or_create(device_type=device.id)

        # Set the premium type, only bother if it's not free.
        premium = form.get_paid()
        if premium:
            addon.update(premium_type=premium)

        if addon.has_icon_in_manifest():
            # Fetch the icon, do polling.
            addon.update(icon_type='image/png')
            tasks.fetch_icon.delay(addon)
        else:
            # In this case there is no need to do any polling.
            addon.update(icon_type='')

        AddonUser(addon=addon, user=request.amo_user).save()
        # Checking it once. Checking it twice.
        AppSubmissionChecklist.objects.create(addon=addon, terms=True,
                                              manifest=True)

        return redirect('submit.app.details', addon.app_slug)

    return jingo.render(request, 'submit/manifest.html', {
        'step': 'manifest',
        'form': form,
        'DEVICE_LOOKUP': DEVICE_LOOKUP
    })


@dev_required
@submit_step('details')
def details(request, addon_id, addon):
    # Name, Slug, Summary, Description, Privacy Policy,
    # Homepage URL, Support URL, Support Email.
    form_basic = AppDetailsBasicForm(request.POST or None, instance=addon,
                                     request=request)
    form_cats = CategoryForm(request.POST or None, product=addon,
                             request=request)
    form_icon = AppFormMedia(request.POST or None, request.FILES or None,
                             instance=addon, request=request)
    form_previews = PreviewFormSet(request.POST or None, prefix='files',
                                   queryset=addon.get_previews())

    # For empty webapp-locale (or no-locale) fields that have
    # form-locale values, duplicate them to satisfy the requirement.
    form_locale = request.COOKIES.get("current_locale", "")
    app_locale = to_language(addon.default_locale)
    for name, value in request.POST.items():
        if value:
            if name.endswith(form_locale):
                basename = name[:-len(form_locale)]
            else:
                basename = name + '_'
            othername = basename + app_locale
            if not request.POST.get(othername, None):
                request.POST[othername] = value
    forms = {
        'form_basic': form_basic,
        'form_cats': form_cats,
        'form_icon': form_icon,
        'form_previews': form_previews,
    }

    if request.POST and all(f.is_valid() for f in forms.itervalues()):
        addon = form_basic.save(addon)
        form_cats.save()
        form_icon.save(addon)
        for preview in form_previews.forms:
            preview.save(addon)

        # If this is an incomplete app from the legacy submission flow, it may
        # not have device types set yet - so assume it works everywhere.
        if not addon.device_types:
            for device in amo.DEVICE_TYPES:
                addon.addondevicetype_set.create(device_type=device)

        tasks.generate_image_assets.delay(addon)

        AppSubmissionChecklist.objects.get(addon=addon).update(details=True)

        make_public = (amo.PUBLIC_IMMEDIATELY
                       if form_basic.cleaned_data.get('publish')
                       else amo.PUBLIC_WAIT)

        # Free apps get pushed for review.
        if addon.premium_type == amo.ADDON_FREE:
            # The developer doesn't want the app published immediately upon
            # review.
            addon.update(status=amo.STATUS_PENDING,
                         make_public=make_public)
        else:
            # Paid apps get STATUS_NULL until payment information has been
            # entered.
            addon.update(status=amo.STATUS_NULL,
                         highest_status=amo.STATUS_PENDING,
                         make_public=make_public)

            # Mark the app as excluded in regions that don't support payments.
            for region in mkt.regions.ALL_REGIONS:
                if not region.has_payments:
                    AddonExcludedRegion.objects.get_or_create(
                        addon=addon, region=region.id)

        return redirect('submit.app.done', addon.app_slug)

    ctx = {
        'step': 'details',
        'addon': addon,
    }
    ctx.update(forms)
    return jingo.render(request, 'submit/details.html', ctx)


@dev_required
def done(request, addon_id, addon):
    # No submit step forced on this page, we don't really care.
    return jingo.render(request, 'submit/done.html',
                        {'step': 'done', 'addon': addon})


@dev_required
def resume(request, addon_id, addon):
    try:
        # If it didn't go through the app submission
        # checklist. Don't die. This will be useful for
        # creating apps with an API later.
        step = addon.appsubmissionchecklist.get_next()
    except ObjectDoesNotExist:
        step = None

    return _resume(addon, step)


def _resume(addon, step):
    if step:
        if step in ['terms', 'manifest']:
            return redirect('submit.app.%s' % step)
        return redirect(reverse('submit.app.%s' % step,
                                args=[addon.app_slug]))

    return redirect(addon.get_dev_url('edit'))


@waffle_switch('mkt-themes')
@login_required
def submit_theme(request):
    form = NewThemeForm(data=request.POST or None,
                        files=request.FILES or None,
                        request=request)
    if request.method == 'POST' and form.is_valid():
        addon = form.save()
        return redirect('submit.theme.done', addon.slug)
    return jingo.render(request, 'themes/submit/submit.html',
                        dict(form=form))


@waffle_switch('mkt-themes')
@login_required
@dev_required
def submit_theme_done(request, addon_id, addon):
    if addon.is_public():
        return redirect(addon.get_url_path())
    return jingo.render(request, 'themes/submit/done.html',
                        dict(addon=addon))