
from decimal import Decimal
import json
from datetime import timedelta
import uuid
from django.urls import reverse
from django.utils import timezone
from django.contrib import messages
from django.db.models import Avg, Count, Q, Exists, OuterRef, Value, Sum
from django.contrib.auth import get_user_model
from django.contrib.admin.views.decorators import staff_member_required
from django.http import HttpResponse, JsonResponse
from django.views.decorators.http import require_POST
from django.views.decorators.csrf import csrf_exempt
from django.contrib.auth.decorators import login_required
from django.shortcuts import get_object_or_404, redirect, render

from core.view_admin import send_transaction_email
from core.views import activate_user_subscription


from .forms import (
    BookingRequestForm,
    CreatorMediaForm,
    MessageReplyForm,
    NewMessageThreadForm,
    PaymentSelectionForm,
    ProfileSearchForm,
    WalletDepositForm,
    WithdrawalRequestForm,
)
from .models import (
    ConnectionRequest,
    MediaBookmark,
    MediaComment,
    MediaReaction,
    Message,
    MessageThread,
    PaidContent,
    CreatorMedia,
    ProfileFollow,
    MediaLike,
    BookingRequest,
    PaymentTransaction,
    SubscriptionPlan,
    UserSubscription,
    InvestmentPlan,
    Investment,
    UserWallet,
    WalletTransaction,
    WithdrawalRequest,
    ReferralBonus,
    ChatMessage,
    create_notification,
)
from .payment_providers import CryptoProvider, PaymentProviderError, PaymentProviderFactory
from users.models import Profile
from django.core.paginator import Paginator
from django.views.decorators.csrf import csrf_exempt


@login_required
def subscription_plans(request):
    plans = SubscriptionPlan.objects.filter(is_active=True).order_by("price_cents")
    return render(request, "core/subscription_plans.html", {"plans": plans})

@login_required
def checkout_subscription(request, plan_id):
    plan = get_object_or_404(SubscriptionPlan, pk=plan_id, is_active=True)
    form = PaymentSelectionForm(request.POST or None)

    if request.method == "POST" and form.is_valid():
        
        provider = form.cleaned_data["provider"]
        
        if provider in ["btc", "usdt"]:
            # Create pending transaction
            transaction = PaymentTransaction.objects.create(
                user=request.user,
                plan=plan,
                provider=provider,
                amount=plan.price_cents,
                currency="USD",
                status=PaymentTransaction.Status.PENDING,
            )
            # Show BTC payment screen
            address = CryptoProvider.get_deposit_address(provider)
            return render(request, "core/crypto_subscription_payment.html", {
                "transaction": transaction,
                "crypto_address": address,
                "provider": provider,
                "plan": plan,
            })
            
        transaction = PaymentTransaction.objects.create(
            user=request.user,
            plan=plan,
            provider=provider,
            amount=plan.price_cents,
            currency=plan.currency,
            status=PaymentTransaction.Status.INITIATED,
        )
        try:
            provider_client = PaymentProviderFactory.build(provider, request)
            redirect_url = provider_client.create_payment(transaction)
            return redirect(redirect_url)
        except PaymentProviderError as exc:
            messages.error(request, f"Payment provider error: {exc}")

    return render(request, "core/payment_checkout.html", {"plan": plan, "form": form})


# def investment_plans(request):
#     plans = InvestmentPlan.objects.filter(is_active=True).order_by("amount")

#     # Investors & activity
#     recent_investments = Investment.objects.select_related(
#         "user", "plan"
#     ).order_by("-started_at")[:8]

#     total_investors = Investment.objects.values("user").distinct().count()
#     total_active_investments = Investment.objects.filter(
#         status=Investment.Status.ACTIVE
#     ).count()

#     # Withdrawals
#     recent_withdrawals = WithdrawalRequest.objects.select_related(
#         "user"
#     ).order_by("-created_at")[:8]

#     pending_withdrawals = WithdrawalRequest.objects.filter(
#         status=WithdrawalRequest.Status.PENDING
#     ).count()

#     context = {
#         "plans": plans,
#         "recent_investments": recent_investments,
#         "total_investors": total_investors,
#         "total_active_investments": total_active_investments,
#         "recent_withdrawals": recent_withdrawals,
#         "pending_withdrawals": pending_withdrawals,
#     }
#     return render(request, "investments/investment_plans.html", context)
@login_required
def investment_plans(request):
    plans = InvestmentPlan.objects.filter(is_active=True).order_by("amount")

    recent_investments = (
        Investment.objects
        .select_related("user", "plan")
        .order_by("-started_at")[:8]
    )

    total_investors = Investment.objects.values("user").distinct().count()
    total_active_investments = Investment.objects.filter(
        status=Investment.Status.ACTIVE
    ).count()

    recent_withdrawals = (
        WithdrawalRequest.objects
        .select_related("user")
        .order_by("-created_at")[:8]
    )

    pending_withdrawals = WithdrawalRequest.objects.filter(
        status=WithdrawalRequest.Status.PENDING
    ).count()

    context = {
        "plans": plans,
        "recent_investments": recent_investments,
        "total_investors": total_investors,
        "total_active_investments": total_active_investments,
        "recent_withdrawals": recent_withdrawals,
        "pending_withdrawals": pending_withdrawals,
    }
    return render(request, "investments/investment_plans.html", context)
    # or "core/investment_plans.html" depending on your template path

@login_required
def investor_list(request):
    if request.user.is_staff:
        wallet  = UserWallet.objects.all()
    else:
        wallet, _ = UserWallet.objects.get_or_create(user=request.user)
    active_investments = request.user.investments.filter(status=Investment.Status.ACTIVE).order_by("-started_at")
    claimed_investments = request.user.investments.filter(status=Investment.Status.COMPLETED).order_by("-ends_at")
    withdrawal_requests = request.user.withdrawal_requests.order_by("-created_at")[:10]
    referral_bonuses = request.user.referral_bonuses.order_by("-created_at")[:10]

    # If matured investments exist, keep status available for claiming.
    matured = active_investments.filter(ends_at__lte=timezone.now())
    total_entitled_after_maturity = matured.aggregate(total=Sum('payout'))['total'] or 0
    next_maturity = active_investments.filter(ends_at__gt=timezone.now()).order_by('ends_at').first()

    total_active_amount = active_investments.aggregate(total=Sum('amount'))['total'] or 0
    total_active_profit = active_investments.aggregate(total=Sum('profit'))['total'] or 0
    active_roi_percent = round((total_active_profit / total_active_amount * 100), 1) if total_active_amount else 0

    remaining_days = [max((investment.ends_at - timezone.now()).days, 0) for investment in active_investments]
    avg_days_to_maturity = round(sum(remaining_days) / len(remaining_days)) if remaining_days else 0

    return render(request, "investments/investment_dashboard.html", {
        "wallet": wallet,
        "active_investments": active_investments,
        "matured_investments": matured,
        "claimed_investments": claimed_investments,
        "withdrawal_requests": withdrawal_requests,
        "referral_bonuses": referral_bonuses,
        "total_entitled_after_maturity": total_entitled_after_maturity,
        "next_maturity": next_maturity,
        "active_roi_percent": active_roi_percent,
        "avg_days_to_maturity": avg_days_to_maturity,
    })


@login_required
def investment_dashboard(request):
    wallet, _ = UserWallet.objects.get_or_create(user=request.user)
    active_investments = request.user.investments.filter(status=Investment.Status.ACTIVE).order_by("-started_at")
    claimed_investments = request.user.investments.filter(status=Investment.Status.COMPLETED).order_by("-ends_at")
    withdrawal_requests = request.user.withdrawal_requests.order_by("-created_at")[:10]
    referral_bonuses = request.user.referral_bonuses.order_by("-created_at")[:10]

    # If matured investments exist, keep status available for claiming.
    matured = active_investments.filter(ends_at__lte=timezone.now())
    total_entitled_after_maturity = matured.aggregate(total=Sum('payout'))['total'] or 0
    next_maturity = active_investments.filter(ends_at__gt=timezone.now()).order_by('ends_at').first()

    total_active_amount = active_investments.aggregate(total=Sum('amount'))['total'] or 0
    total_active_profit = active_investments.aggregate(total=Sum('profit'))['total'] or 0
    active_roi_percent = round((total_active_profit / total_active_amount * 100), 1) if total_active_amount else 0

    remaining_days = [max((investment.ends_at - timezone.now()).days, 0) for investment in active_investments]
    avg_days_to_maturity = round(sum(remaining_days) / len(remaining_days)) if remaining_days else 0

    return render(request, "investments/investment_dashboard.html", {
        "wallet": wallet,
        "active_investments": active_investments,
        "matured_investments": matured,
        "claimed_investments": claimed_investments,
        "withdrawal_requests": withdrawal_requests,
        "referral_bonuses": referral_bonuses,
        "total_entitled_after_maturity": total_entitled_after_maturity,
        "next_maturity": next_maturity,
        "active_roi_percent": active_roi_percent,
        "avg_days_to_maturity": avg_days_to_maturity,
    })


@staff_member_required
def admin_investment_management(request):
    total_invested = Investment.objects.aggregate(total=Sum('amount'))['total'] or 0
    total_active = Investment.objects.filter(status=Investment.Status.ACTIVE).aggregate(total=Sum('amount'))['total'] or 0
    total_completed = Investment.objects.filter(status=Investment.Status.COMPLETED).aggregate(total=Sum('payout'))['total'] or 0
    total_withdrawn = Investment.objects.filter(is_withdrawn=True).aggregate(total=Sum('payout'))['total'] or 0
    total_wallet_balance = UserWallet.objects.aggregate(total=Sum('balance'))['total'] or 0
    total_wallet_users = UserWallet.objects.count()
    average_wallet_balance = UserWallet.objects.aggregate(avg=Avg('balance'))['avg'] or 0
    pending_deposits = WalletTransaction.objects.filter(
        transaction_type=WalletTransaction.Type.DEPOSIT,
        status=WalletTransaction.Status.PENDING,
    ).count()
    top_wallets = UserWallet.objects.select_related('user').annotate(
        active_investments=Count(
            'user__investments',
            filter=Q(user__investments__status=Investment.Status.ACTIVE),
        )
    ).order_by('-balance')[:10]
    user_wallet_summaries = UserWallet.objects.select_related('user').annotate(
        active_investments=Count(
            'user__investments',
            filter=Q(user__investments__status=Investment.Status.ACTIVE),
        ),
        completed_investments=Count(
            'user__investments',
            filter=Q(user__investments__status=Investment.Status.COMPLETED),
        )
    ).order_by('-balance')[:10]
    recent_wallet_transactions = WalletTransaction.objects.select_related('user').order_by('-created_at')[:20]

    recent_plans = InvestmentPlan.objects.filter(is_active=True).order_by('amount')
    recent_investments = Investment.objects.select_related('user', 'plan').order_by('-started_at')[:20]
    recent_withdrawals = WithdrawalRequest.objects.select_related('user').order_by('-created_at')[:20]

    # Add these lines for crypto integration
    pending_crypto_deposits = WalletTransaction.objects.filter(
        status=WalletTransaction.Status.PENDING,
        transaction_type=WalletTransaction.Type.DEPOSIT
    ).count()

    pending_withdrawals = WithdrawalRequest.objects.filter(
        status=WithdrawalRequest.Status.PENDING
    ).count()
    
    context = {
        'total_invested': total_invested,
        'total_active': total_active,
        'total_completed': total_completed,
        'total_withdrawn': total_withdrawn,
        'total_wallet_balance': total_wallet_balance,
        'total_wallet_users': total_wallet_users,
        'average_wallet_balance': average_wallet_balance,
        'pending_deposits': pending_deposits,
        'top_wallets': top_wallets,
        'user_wallet_summaries': user_wallet_summaries,
        'recent_wallet_transactions': recent_wallet_transactions,
        'recent_plans': recent_plans,
        'recent_investments': recent_investments,
        'recent_withdrawals': recent_withdrawals,
        'pending_crypto_deposits': pending_crypto_deposits,
        'pending_withdrawals': pending_withdrawals,
    }
    return render(request, 'investments/admin_investment_management.html', context)


@login_required
def checkout_investment(request, plan_id):
    plan = get_object_or_404(InvestmentPlan, pk=plan_id, is_active=True)
    wallet, _ = UserWallet.objects.get_or_create(user=request.user)

    if request.method == "POST":
        if wallet.balance < plan.amount:
            messages.error(request, "Insufficient wallet balance. Please fund your wallet before investing.")
            return redirect("core:wallet_deposit")
        else:
            investment = Investment.objects.create(
                user=request.user,
                plan=plan,
                started_at=timezone.now(),
                ends_at=timezone.now() + timedelta(days=plan.duration_days),
                amount=plan.amount,
                profit_cents=plan.profit_amount,
                investment_payout=plan.payout_amount,
            )
            wallet.withdraw(plan.amount)

            if request.user.referred_by:
                bonus_cents = int(plan.amount * 0.05)
                ReferralBonus.objects.create(
                    user=request.user.referred_by,
                    referred_user=request.user,
                    investment=investment,
                    bonus_cents=bonus_cents,
                )
                referrer_wallet, _ = UserWallet.objects.get_or_create(user=request.user.referred_by)
                referrer_wallet.deposit(bonus_cents)
                create_notification(
                    user=request.user.referred_by,
                    verb=f"You earned a referral bonus of {investment.plan.currency} {bonus_cents / 100:.2f} from {request.user.username}.",
                    target_url=reverse("core:investment_dashboard"),
                )

            messages.success(request, "Your investment has been created. It will mature after the plan duration ends.")
            return redirect("core:investment_dashboard")

    return render(request, "investments/investment_checkout.html", {"plan": plan, "wallet": wallet})


@login_required
def wallet_deposit(request):
    wallet, _ = UserWallet.objects.get_or_create(user=request.user)
    form = WalletDepositForm(request.POST or None)

    next_url = request.GET.get("next") or request.POST.get("next")
    suggested_amount = request.GET.get("amount") or request.POST.get("amount")

    if suggested_amount and not form.is_bound:
        try:
            form.fields["amount"].initial = Decimal(str(suggested_amount))
        except Exception:
            pass

    if request.method == "POST" and form.is_valid():
        provider = form.cleaned_data["provider"]
        amount_value = form.cleaned_data["amount"]
        amount = int(amount_value * 100)

        # ---------- CRYPTO ----------
        if provider in ["btc", "usdt"]:
            transaction = WalletTransaction.objects.create(
                user=request.user,
                transaction_type=WalletTransaction.Type.DEPOSIT,
                provider=provider,
                amount=amount,
                currency="USD",
                status=WalletTransaction.Status.PENDING,
            )

            if request.POST.get("tx_hash"):
                tx_hash = request.POST.get("tx_hash").strip()
                success = CryptoProvider.verify_deposit(transaction, tx_hash)

                if success:
                    messages.success(request, f"Deposit of ${amount_value:.2f} credited successfully!")
                    # Only now is it safe to redirect back
                    if next_url:
                        return redirect(next_url)
                    return redirect("core:investment_dashboard")
                else:
                    messages.warning(request, "Payment could not be auto-verified. Admin will review it.")
                    # Do NOT redirect to next yet – stay on deposit page or go to dashboard
                    return redirect("core:investment_dashboard")

            # Show QR / address screen (do not redirect)
            address = CryptoProvider.generate_unique_address(provider, transaction)
            return render(request, "investments/wallet_deposit.html", {
                "form": form,
                "wallet": wallet,
                "crypto_address": address,
                "provider": provider.upper(),
                "amount": amount_value,
                "transaction": transaction,
                "next_url": next_url,
            })

        # ---------- BANK / OTHER ----------
        else:
            WalletTransaction.objects.create(
                user=request.user,
                transaction_type=WalletTransaction.Type.DEPOSIT,
                provider=provider,
                amount=amount,
                currency="USD",
                status=WalletTransaction.Status.PENDING,
            )
            messages.success(request, "Deposit request submitted. It will be reviewed shortly.")
            # For pending bank deposits we usually do NOT auto-redirect to next
            return redirect("core:investment_dashboard")

    return render(request, "investments/wallet_deposit.html", {
        "form": form,
        "wallet": wallet,
        "next_url": next_url,
        "suggested_amount": suggested_amount,
    })
    
@login_required
def withdrawal_request(request):
    wallet, _ = UserWallet.objects.get_or_create(user=request.user)
    form = WithdrawalRequestForm(request.POST or None)
    minimum_cents = 1000

    if request.method == "POST":
        if form.is_valid():
            provider = form.cleaned_data["provider"]
            amount_value = form.cleaned_data["amount"]
            amount = int(amount_value * 100)

            if amount < minimum_cents:
                form.add_error("amount", "Minimum withdrawal amount is $10.")
                messages.error(request, "Please enter an amount of at least $10.")
            elif amount > wallet.balance:
                form.add_error("amount", "Insufficient wallet balance for this withdrawal.")
                messages.error(request, "You do not have enough funds in your wallet for this withdrawal.")
            else:
                try:
                    wallet.withdraw(amount)
                    WithdrawalRequest.objects.create(
                        user=request.user,
                        amount=amount,
                        currency="USD",
                        provider=provider,
                        status=WithdrawalRequest.Status.PENDING,
                    )
                except ValueError as exc:
                    form.add_error(None, str(exc))
                    messages.error(request, f"Unable to submit withdrawal: {exc}")
                else:
                    messages.success(request, "Withdrawal request submitted. Processing will complete within 24 hours.")
                    return redirect("core:investment_dashboard")
        else:
            messages.error(request, "Please correct the highlighted fields before submitting your withdrawal request.")

    return render(request, "investments/withdrawal_request.html", {"form": form, "wallet": wallet, "minimum_amount": 10})


@login_required
def claim_investment_payout(request, investment_id):
    investment = get_object_or_404(Investment, pk=investment_id, user=request.user, status=Investment.Status.ACTIVE)
    if not investment.is_mature:
        messages.warning(request, "This investment has not matured yet.")
        return redirect("core:investment_dashboard")

    wallet, _ = UserWallet.objects.get_or_create(user=request.user)
    wallet.deposit(investment.investment_payout)
    investment.status = Investment.Status.COMPLETED
    investment.is_withdrawn = True
    investment.save(update_fields=["status", "is_withdrawn", "updated_at"])

    messages.success(request, "Investment payout credited to your wallet. You can now request a withdrawal.")
    return redirect("core:investment_dashboard")


@login_required
def payment_return(request, provider, transaction_id):
    transaction = get_object_or_404(PaymentTransaction, pk=transaction_id, provider=provider, user=request.user)
    provider_client = PaymentProviderFactory.build(provider, request)
    try:
        provider_client.verify_payment(transaction, request=request)
    except PaymentProviderError as exc:
        messages.warning(request, f"Payment verification warning: {exc}")

    if transaction.is_successful:
        title = "Payment completed"
        message = "Your subscription payment was successful."
    elif transaction.status == PaymentTransaction.Status.FAILED:
        title = "Payment failed"
        message = "Your payment did not succeed."
    else:
        title = "Payment pending"
        message = "Your payment is being processed. You will receive confirmation shortly."
    return render(
        request,
        "core/payment_return.html",
        {"transaction": transaction, "title": title, "message": message},
    )



@csrf_exempt
@require_POST
def payment_webhook(request, provider):

    try:
        payload = request.body.decode("utf-8")
        event = json.loads(payload)
    except Exception:
        return HttpResponse(status=400)

    try:
        provider_client = PaymentProviderFactory.build(provider, request)
        payment = provider_client.handle_webhook(event)
        if payment and payment.is_successful:
            activate_user_subscription(payment.user, payment.plan, provider, transaction=payment)
            create_notification(
                user=payment.user,
                verb=f"Your {payment.plan.name} subscription payment succeeded.",
                target_url=request.build_absolute_uri(
                    reverse("core:payment_return", args=[provider, payment.pk])
                ),
            )
        return HttpResponse(status=204)
    except PaymentProviderError:
        return HttpResponse(status=400)


# ===================== CRYPTO WEBHOOK =====================
@csrf_exempt
@require_POST
def crypto_webhook(request):
    """Webhook for BTC / USDT TRC20 deposits"""
    try:
        payload = json.loads(request.body)
    except Exception:
        return HttpResponse(status=400)

    tx_hash = payload.get('tx_hash')
    amount = payload.get('amount')
    provider = payload.get('provider')  # 'btc' or 'usdt'
    user_id = payload.get('user_id')
    reference = payload.get('reference')

    if not all([tx_hash, amount, provider, user_id]):
        return HttpResponse(status=400)

    try:
        transaction = WalletTransaction.objects.get(
            reference=reference,
            provider=provider,
            status=WalletTransaction.Status.PENDING
        )
        
        if CryptoProvider.verify_deposit(transaction, tx_hash):
            create_notification(
                user=transaction.user,
                verb=f"Your {provider.upper()} deposit of ${transaction.amount/100:.2f} has been confirmed.",
                target_url=reverse("core:investment_dashboard")
            )
            return HttpResponse(status=200)
    except WalletTransaction.DoesNotExist:
        # Log for manual review
        pass

    return HttpResponse(status=400)

@csrf_exempt
@require_POST
def crypto_subscription_webhook(request):
    try:
        data = json.loads(request.body)
        tx_hash = data.get('tx_hash')
        reference = data.get('reference')
        
        transaction = PaymentTransaction.objects.get(reference=reference)
        
        if CryptoProvider.auto_verify_for_subscription(transaction, tx_hash):
            activate_user_subscription(transaction.user, transaction.plan, transaction.provider, transaction)
            return HttpResponse(status=200)
    except:
        pass
    return HttpResponse(status=400)


@staff_member_required
def admin_btc_subscriptions(request):
    """Admin view for manual review of Bitcoin subscriptions"""
    pending_btc_payments = PaymentTransaction.objects.filter(
        provider__in=['btc', 'usdt'],
        status=PaymentTransaction.Status.PENDING
    ).select_related('user', 'plan').order_by('-created_at')

    context = {
        'pending_btc_payments': pending_btc_payments,
    }
    return render(request, 'investments/admin_btc_subscriptions.html', context)


@staff_member_required
@require_POST
def admin_approve_btc_subscription(request, tx_id):
    """Manually approve a BTC/USDT subscription"""
    transaction = get_object_or_404(
        PaymentTransaction, 
        pk=tx_id, 
        provider__in=['btc', 'usdt'],
        status=PaymentTransaction.Status.PENDING
    )
    
    transaction.status = PaymentTransaction.Status.COMPLETED
    transaction.save()
    
    activate_user_subscription(
        transaction.user, 
        transaction.plan, 
        transaction.provider, 
        transaction
    )
    
    send_transaction_email(
        transaction.user,
        "✅ Subscription Activated",
        f"Your {transaction.plan.name} subscription has been manually approved."
    )
    
    messages.success(request, f"Subscription for {transaction.user.username} activated.")
    return redirect('core:admin_btc_subscriptions')

@login_required
def crypto_payment_success(request, transaction_id):
    transaction = get_object_or_404(
        PaymentTransaction, 
        pk=transaction_id, 
        user=request.user
    )
    
    if transaction.status != PaymentTransaction.Status.COMPLETED:
        messages.warning(request, "Payment is still being confirmed.")
    
    return render(request, "investments/crypto_payment_success.html", {
        "transaction": transaction
    })
    
    