import json
import logging
import time

from django.conf import settings
from django.core.cache import cache

from tower import ungettext as _

from addons.models import Addon
import amo
from amo.helpers import absolutify
from amo.utils import send_mail
from market.models import PaypalCheckStatus
from paypal.check import Check
from users.utils import get_task_user

from celeryutils import task
from jingo import env
from waffle import Sample, switch_is_active

log = logging.getLogger('z.market.task')
key = 'amo:market:check_paypal'
failures = '%s:failure' % key
passes = '%s:passes' % key


def check_paypal_multiple(ids, limit=None):
    """
    Setup redis so that we can store the count of addons tested and failed
    and spot when the test is completed.

    ids: Is the add-on ids we'll be checking.
    limit: The percentage of add-ons to change before we assume something
           has gone wrong. Setting this to zero (not recommended) disables it.
           If not set, we'll use the paypal-disabled-limit waffle sample
           value.
    """
    if limit is None:
        limit = Sample.objects.get(name='paypal-disabled-limit').percent

    log.info('Starting run of paypal addon checks: %s' % len(ids))
    cache.set(key, [time.time(), len(ids), float(limit)])
    PaypalCheckStatus.objects.all().delete()
    return ids


def _check_paypal_completed():
    started, count, limit = cache.get(key)
    limit, count = float(limit), int(count)
    if PaypalCheckStatus.objects.count() < count:
        return False
    failed = (PaypalCheckStatus.objects
              .filter(failure_data__isnull=False))
    passed = (PaypalCheckStatus.objects
              .filter(failure_data__isnull=True)
              .count())
    context = {'checked': count,
               'failed_addons': failed,
               'failed': len(failed),
               'passed': passed,
               'limit': limit, 'rate': (len(failed) / float(count)) * 100,
               'do_disable': switch_is_active('paypal-disable')}
    _notify(context)
    return True


def _notify(context):
    """
    Notify the admins or the developers what happened. Performing a sanity
    check in case something went wrong.
    """
    log.info('Completed run of paypal addon checks: %s' % context['checked'])
    failure_list = []

    if context['limit'] and context['rate'] > context['limit']:
        # This is too cope with something horrible going wrong like, paypal
        # goes into maintenance mode, or netops changes something and all of
        # a sudden all the apps start failing their paypal checks.
        #
        # It would really suck if one errant current job disabled every app
        # on the Marketplace. So this is an attempt to sanity check this.
        for f in context['failed_addons']:
            failure_list.append(absolutify(f.addon.get_url_path()))

        context['failure_list'] = failure_list
        log.info('Too many failed: %s%%, aborting.' % context['limit'])
        template = 'market/emails/check_error.txt'
        send_mail('Cron job error on checking addons',
                  env.get_template(template).render(context),
                  recipient_list=[settings.FLIGTAR],
                  from_email=settings.NOBODY_EMAIL)

    else:
        if not context['failed_addons']:
            return

        for f in context['failed_addons']:

            addon = f.addon
            url = absolutify(addon.get_url_path())
            # Add this to a list so we can tell the admins who got disabled.
            failure_list.append(url)
            if not context['do_disable']:
                continue

            # Write to the developers log that it failed to pass and update
            # the status of the addon.
            amo.log(amo.LOG.PAYPAL_FAILED, addon, user=get_task_user())
            addon.update(status=amo.STATUS_DISABLED)
            authors = [u.email for u in addon.authors.all()]
            if addon.is_webapp():
                template = 'market/emails/check_developer_app.txt'
                subject = _('App disabled on the Firefox Marketplace.')
            else:
                template = 'market/emails/check_developer_addon.txt'
                subject = _('Add-on disabled on the Firefox Marketplace.')

            # Now email the developer and tell them the bad news.
            send_mail(subject,
                      env.get_template(template).render({
                          'addon': addon,
                          'errors': json.loads(f.failure_data)
                      }),
                      recipient_list=authors,
                      from_email=settings.NOBODY_EMAIL)

        context['failure_list'] = failure_list
        # Now email the admins and tell them what happened.
        template = 'market/emails/check_summary.txt'
        send_mail('Cron job disabled %s add-ons' % context['failed'],
                  env.get_template(template).render(context),
                  recipient_list=[settings.FLIGTAR],
                  from_email=settings.NOBODY_EMAIL)


@task(rate_limit='4/m')
def check_paypal(ids, check=None, **kw):
    """
    Checks an addon against PayPal for the following things:
    - that the refund token is still there
    - that they have enough currency
    If the addon fails any of these tests then we'll log, email the developer
    and alter the apps status so that it can't be bought.
    This will be doing lots of pings to PayPal so I expect it to be pretty
    slow.
    """
    log.info('[%s@%s] checking paypal for addons starting with: %s'
             % (len(ids), check_paypal.rate_limit, ids[0]))

    if check is None:
        check = Check
    for id in ids:
        try:
            addon = Addon.objects.get(pk=id)
        except Addon.DoesNotExist:
            log.info('No addon: %s' % id)
            continue

        try:
            log.info('Checking paypal for: %s' % addon.id)
            result = check(addon=addon)
            result.all()
            if result.passed:
                PaypalCheckStatus.objects.create(addon=addon)
                log.info('Paypal checks all passed for: %s' % id)
            else:
                PaypalCheckStatus.objects.create(
                    addon=addon,
                    failure_data=json.dumps(result.errors))
                log.info('Paypal checks failed for: %s' % id)

        except:
            # Note I'm marking this as a pass, because marking it as a failure
            # would cause the app to be marked as disabled and I think that's
            # the wrong thing to do.
            log.error('Paypal check failed: %s' % id, exc_info=True)
            PaypalCheckStatus.objects.create(addon=addon)

        # Finally call to see if we've finished.
        _check_paypal_completed()

@@ -122,17 +122,16 @@
 import u
-n
 gettext 

fix unngettext -> ugettext (thanks, @potch)