#!/usr/bin/env python
import hashlib

from django.conf import settings
from django.utils.encoding import smart_str

from paypal.utils import warn_untested


def get_sha1_hexdigest(salt, raw_password):
    encoded_string = (smart_str(salt) + smart_str(raw_password)).encode("utf-8")
    return hashlib.sha1(encoded_string).hexdigest()


def duplicate_txn_id(ipn_obj):
    """
    Returns True if a record with this transaction id exists and its
    payment_status has not changed.
    This function has been completely changed from its previous implementation
    where it used to specifically only check for a Pending->Completed
    transition.

    """

    # get latest similar transaction(s)
    similars = (
        ipn_obj.__class__._default_manager.filter(txn_id=ipn_obj.txn_id)
        .exclude(id=ipn_obj.id)
        .exclude(flag=True)
        .order_by("-created_at")[:1]
    )

    if len(similars) > 0:
        # we have a similar transaction, has the payment_status changed?
        return similars[0].payment_status == ipn_obj.payment_status

    return False


def make_secret(form_instance, secret_fields=None):
    """
    Returns a secret for use in a EWP form or an IPN verification based on a
    selection of variables in params. Should only be used with SSL.

    """
    # @@@ Moved here as temporary fix to avoid dependancy on auth.models.
    # @@@ amount is mc_gross on the IPN - where should mapping logic go?
    # @@@ amount / mc_gross is not nessecarily returned as it was sent - how to use it? 10.00 vs. 10.0
    # @@@ the secret should be based on the invoice or custom fields as well - otherwise its always the same.

    # Build the secret with fields availible in both PaymentForm and the IPN. Order matters.
    if secret_fields is None:
        secret_fields = ["business", "item_name"]

    data = ""
    for name in secret_fields:
        if hasattr(form_instance, "cleaned_data"):
            if name in form_instance.cleaned_data:
                data += str(form_instance.cleaned_data[name])
        else:
            # Initial data passed into the constructor overrides defaults.
            if name in form_instance.initial:
                data += str(form_instance.initial[name])
            elif name in form_instance.fields and form_instance.fields[name].initial is not None:
                data += str(form_instance.fields[name].initial)

    secret = get_sha1_hexdigest(settings.SECRET_KEY, data)
    return secret


def check_secret(form_instance, secret):
    """
    Returns true if received `secret` matches expected secret for form_instance.
    Used to verify IPN.

    """
    warn_untested()
    # @@@ add invoice & custom
    # secret_fields = ['business', 'item_name']
    return make_secret(form_instance) == secret
