from flask import Blueprint, jsonify, request, current_app, redirect, url_for
from flask_login import current_user, login_required
import stripe
from app.db import get_db_controller
from app.utils import generate_unique_sub_name, generate_unique_code

stripe_bp = Blueprint('stripe', __name__)

@stripe_bp.route('/create-checkout-session', methods=['POST'])
@login_required
def create_checkout_session():
    stripe.api_key = current_app.config['STRIPE_SECRET_KEY']
    try:
        checkout_session = stripe.checkout.Session.create(
            customer_email=current_user.email,
            client_reference_id=str(current_user.id),
            line_items=[
                {
                    'price': current_app.config['SUBSCRIPTION_PRICE_ID'],
                    'quantity': 1,
                },
            ],
            mode='subscription',
            success_url=url_for('main.dashboard', _external=True) + '?session_id={CHECKOUT_SESSION_ID}',
            cancel_url=url_for('main.dashboard', _external=True),
        )
        return redirect(checkout_session.url, code=303)
    except Exception as e:
        return str(e)

@stripe_bp.route('/webhook', methods=['POST'])
def webhook():
    event = None
    payload = request.data
    sig_header = request.headers['STRIPE_SIGNATURE']
    
    try:
        event = stripe.Webhook.construct_event(
            payload, sig_header, current_app.config['STRIPE_WEBHOOK_SECRET']
        )
    except ValueError as e:
        return jsonify(success=False)
    except stripe.error.SignatureVerificationError as e:
        return jsonify(success=False)

    db = get_db_controller()

    if event['type'] == 'checkout.session.completed':
        session = event['data']['object']
        # fulfilling the order
        user_id = session.get('client_reference_id')
        str_sub_id = session.get('subscription')
        customer_id = session.get('customer')
        
        if user_id:
            # Generate unique stuff
            user = db.get_user_by_id(user_id)
            if user:
                sub_name = generate_unique_sub_name(user['username'])
                code = generate_unique_code()
                
                db.create_subscription(
                    user_id=user_id,
                    stripe_sub_id=str_sub_id,
                    customer_id=customer_id,
                    sub_name=sub_name,
                    unique_code=code,
                    status='active'
                )

    elif event['type'] == 'customer.subscription.deleted':
        subscription = event['data']['object']
        db.update_subscription_status(subscription.id, 'canceled')

    return jsonify(success=True)

@stripe_bp.route('/cancel-subscription', methods=['POST'])
@login_required
def cancel_subscription():
    sub_id = request.form.get('sub_id') # Stripe Sub ID
    stripe.api_key = current_app.config['STRIPE_SECRET_KEY']
    
    try:
        stripe.Subscription.delete(sub_id)
        # Webhook will handle DB update, but we can do it optimistically or wait.
        # Ideally, we wait for webhook, but user wants feedback.
        db = get_db_controller()
        db.update_subscription_status(sub_id, 'canceled')
        return redirect(url_for('main.dashboard'))
    except Exception as e:
        return str(e)

@stripe_bp.route('/reactivate-subscription', methods=['POST'])
@login_required
def reactivate_subscription():
    # Reactivating a canceled subscription usually means creating a new one in Stripe 
    # or resuming if it's in grace period.
    # The prompt says: "They will be able to reactive old accounts if they want to."
    # Implementation: Redirect to checkout again? Or use Stripe portal?
    # Simpler: Redirect to create-checkout-session to buy a new one, 
    # but maybe pre-fill data? 
    # If they want to "reactivate" an OLD one (same name/code?), we need logic to claim that name/code.
    # Requirement: "reactive old accounts". 
    # Allow user to click "Reactivate" on a "canceled" sub.
    # We can start a new checkout. If successful, we generate NEW name/code by default.
    # If we want to keep old, we need to pass logic. 
    # Let's assume standard behavior: Buy new subscription.
    return redirect(url_for('stripe.create_checkout_session'))

