from django.shortcuts import render, get_object_or_404, redirect
from django.http import JsonResponse, HttpResponseBadRequest
from django.views.decorators.http import require_http_methods
from django.views.decorators.csrf import csrf_exempt
from django.contrib import messages
from django.conf import settings
from django.core.mail import send_mail
from django.template.loader import render_to_string
from django.utils import timezone
from django.urls import reverse
import stripe
import hashlib
import hmac

from .models import Hat, Customer, Purchase


stripe.api_key = settings.STRIPE_SECRET_KEY


def home(request):
    available_hats = Hat.objects.filter(
        status__in=[Hat.Status.AVAILABLE, Hat.Status.FIRST_DIBS]
    ).order_by("-created_at")

    customer = None
    customer_email = request.session.get("customer_email")
    if customer_email:
        try:
            customer = Customer.objects.get(email=customer_email, is_active=True)
        except Customer.DoesNotExist:
            customer = None

    hats_with_access = []
    for hat in available_hats:
        hat_dict = {
            "id": hat.id,
            "name": hat.name,
            "slug": hat.slug,
            "price": hat.price,
            "image": hat.image.url if hat.image else None,
            "status": hat.status,
            "status_display": hat.status_display,
            "can_purchase": hat.can_purchase(customer),
        }
        hats_with_access.append(hat_dict)

    context = {
        "hats": hats_with_access,
        "customer": customer,
        "stripe_public_key": settings.STRIPE_PUBLISHABLE_KEY,
    }
    return render(request, "hats/home.html", context)


def archive(request):
    sold_hats = Hat.objects.filter(status=Hat.Status.SOLD).order_by("-sold_at")

    context = {
        "hats": sold_hats,
    }
    return render(request, "hats/archive.html", context)


def hat_detail(request, slug):
    hat = get_object_or_404(Hat, slug=slug)

    customer = None
    customer_email = request.session.get("customer_email")
    if customer_email:
        try:
            customer = Customer.objects.get(email=customer_email, is_active=True)
        except Customer.DoesNotExist:
            customer = None

    if hat.status == Hat.Status.SOLD:
        context = {
            "hat": hat,
            "is_sold": True,
        }
        return render(request, "hats/hat_detail.html", context)

    if hat.status == Hat.Status.FIRST_DIBS and not hat.can_purchase(customer):
        messages.info(
            request,
            "This hat is currently available for First Dibs to prior customers. "
            "Enter your email to verify your eligibility.",
        )
        return redirect("verify_email")

    context = {
        "hat": hat,
        "is_sold": False,
        "can_purchase": hat.can_purchase(customer),
        "customer": customer,
        "stripe_public_key": settings.STRIPE_PUBLISHABLE_KEY,
    }
    return render(request, "hats/hat_detail.html", context)


@require_http_methods(["GET", "POST"])
def verify_email(request):
    if request.method == "POST":
        email = request.POST.get("email", "").strip().lower()
        if not email:
            messages.error(request, "Please enter a valid email address.")
            return redirect("verify_email")

        try:
            customer = Customer.objects.get(email=email, is_active=True)
            if customer.has_purchased:
                request.session["customer_email"] = email
                request.session["customer_id"] = customer.id
                messages.success(
                    request,
                    f"Welcome back, {customer.name}! You have First Dibs access.",
                )
                return redirect("home")
            else:
                messages.info(
                    request,
                    "You need to make a purchase first to get First Dibs access.",
                )
        except Customer.DoesNotExist:
            messages.error(request, "No customer found with that email address.")

        return redirect("verify_email")

    return render(request, "hats/verify_email.html")


def clear_session(request):
    if "customer_email" in request.session:
        del request.session["customer_email"]
    if "customer_id" in request.session:
        del request.session["customer_id"]
    messages.success(request, "You have been logged out.")
    return redirect("home")


@require_http_methods(["GET", "POST"])
def checkout(request, slug):
    hat = get_object_or_404(Hat, slug=slug)

    if hat.status == Hat.Status.SOLD:
        messages.error(request, "This hat has already been sold.")
        return redirect("home")

    customer = None
    customer_email = request.session.get("customer_email")
    if customer_email:
        try:
            customer = Customer.objects.get(email=customer_email, is_active=True)
        except Customer.DoesNotExist:
            customer = None

    if not hat.can_purchase(customer):
        if hat.status == Hat.Status.FIRST_DIBS:
            messages.info(
                request,
                "This hat requires First Dibs access. Please verify your email.",
            )
            return redirect("verify_email")
        messages.error(request, "This hat is not available for purchase.")
        return redirect("home")

    if request.method == "POST":
        email = request.POST.get("email", "").strip().lower()
        name = request.POST.get("name", "").strip()

        if not email or not name:
            messages.error(request, "Please provide both name and email.")
            return redirect("checkout", slug=slug)

        try:
            customer_obj, created = Customer.objects.get_or_create(
                email=email, defaults={"name": name}
            )

            if not created and customer_obj.name != name:
                customer_obj.name = name
                customer_obj.save()

            request.session["customer_email"] = email
            request.session["customer_id"] = customer_obj.id

            intent = stripe.PaymentIntent.create(
                amount=int(hat.price * 100),
                currency="usd",
                metadata={
                    "hat_id": hat.id,
                    "hat_name": hat.name,
                    "customer_email": email,
                    "customer_name": name,
                },
            )

            context = {
                "hat": hat,
                "customer": customer_obj,
                "stripe_public_key": settings.STRIPE_PUBLISHABLE_KEY,
                "client_secret": intent.client_secret,
            }
            return render(request, "hats/payment.html", context)

        except stripe.error.StripeError as e:
            messages.error(request, f"Payment error: {str(e)}")
            return redirect("checkout", slug=slug)

    context = {
        "hat": hat,
        "stripe_public_key": settings.STRIPE_PUBLISHABLE_KEY,
    }
    return render(request, "hats/checkout.html", context)


@csrf_exempt
@require_http_methods(["POST"])
def stripe_webhook(request):
    payload = request.body
    sig_header = request.META.get("HTTP_STRIPE_SIGNATURE", "")
    endpoint_secret = settings.STRIPE_WEBHOOK_SECRET

    try:
        event = stripe.Webhook.construct_event(payload, sig_header, endpoint_secret)
    except ValueError:
        return HttpResponseBadRequest("Invalid payload")
    except stripe.error.SignatureVerificationError:
        return HttpResponseBadRequest("Invalid signature")

    if event["type"] == "payment_intent.succeeded":
        intent = event["data"]["object"]
        handle_successful_payment(intent)

    return JsonResponse({"status": "success"})


def handle_successful_payment(intent):
    metadata = intent.get("metadata", {})
    hat_id = metadata.get("hat_id")
    customer_email = metadata.get("customer_email")
    customer_name = metadata.get("customer_name")

    if not hat_id:
        return

    try:
        hat = Hat.objects.get(id=hat_id)

        customer, _ = Customer.objects.get_or_create(
            email=customer_email, defaults={"name": customer_name}
        )

        if not Purchase.objects.filter(stripe_payment_intent_id=intent["id"]).exists():
            Purchase.objects.create(
                customer=customer,
                hat=hat,
                stripe_payment_intent_id=intent["id"],
                amount_paid=hat.price,
            )

            hat.status = Hat.Status.SOLD
            hat.sold_at = timezone.now()
            hat.stripe_payment_intent_id = intent["id"]
            hat.save()

    except Hat.DoesNotExist:
        pass


def generate_verification_token(email):
    secret = settings.SECRET_KEY.encode()
    token = hmac.new(secret, email.encode(), hashlib.sha256).hexdigest()
    return token


def send_first_dibs_notifications(hat):
    prior_customers = Customer.objects.filter(
        is_active=True, purchases__isnull=False
    ).distinct()

    for customer in prior_customers:
        hat_url = request.build_absolute_uri(
            reverse("hat_detail", kwargs={"slug": hat.slug})
        )

        subject = f"First Dibs: New Hat Available - {hat.name}"
        message = f"""
Hi {customer.name},

A new hat has been added to HatYeti.com!

{hat.name}
{hat.description}
Price: ${hat.price}

You have exclusive access for the next 3 days before it goes public.

Get it here: {hat_url}

Happy hatting!
- The Hat Yeti
        """.strip()

        try:
            send_mail(
                subject=subject,
                message=message,
                from_email=settings.DEFAULT_FROM_EMAIL,
                recipient_list=[customer.email],
                html_message=render_to_string(
                    "hats/emails/first_dibs.html",
                    {
                        "customer": customer,
                        "hat": hat,
                        "hat_url": hat_url,
                    },
                ),
            )
        except Exception:
            pass
