"""
Payment Routes - QR Code Payment System
Handles payment methods, screenshot submissions, and verification
"""
from flask import Blueprint, request, jsonify, g
from utils import require_api_key, format_api_response, create_error_response
from auth.jwt_manager import require_auth
from database import get_cached_connection
import logging
import os
from datetime import datetime
from werkzeug.utils import secure_filename
import uuid
import json

# Duplicate helper from enrollment_routes.py to avoid circular imports
def _validate_and_apply_coupon_logic(cursor, user_id, course_id, coupon_code, original_price):
    """Validate and calculate coupon discount"""
    try:
        # Get coupon details
        cursor.execute("""
            SELECT 
                id, name, balance, coupon_type, discount_value, 
                min_purchase_amount, max_discount_amount, usage_limit, used_count,
                valid_from, valid_until, applicable_courses, applicable_institutes
            FROM coupons 
            WHERE code = %s AND is_active = 1
        """, (coupon_code,))
        
        coupon = cursor.fetchone()
        if not coupon:
            return {'success': False, 'message': 'Invalid coupon code'}
        
        # Check validity dates
        now = datetime.now()
        if coupon['valid_from'] and coupon['valid_from'] > now:
            return {'success': False, 'message': 'Coupon is not yet valid'}
        
        if coupon['valid_until'] and coupon['valid_until'] < now:
            return {'success': False, 'message': 'Coupon has expired'}
        
        # Check usage limit
        if coupon['usage_limit'] and coupon['used_count'] >= coupon['usage_limit']:
            return {'success': False, 'message': 'Coupon usage limit reached'}
        
        # Check minimum purchase amount
        if coupon['min_purchase_amount'] and original_price < float(coupon['min_purchase_amount']):
            return {'success': False, 'message': f'Minimum purchase amount is NPR {coupon["min_purchase_amount"]}'}
        
        # Check if user has already used this coupon (for assigned coupons)
        cursor.execute("""
            SELECT is_used FROM user_coupon_assignments 
            WHERE user_id = %s AND coupon_id = %s
        """, (user_id, coupon['id']))
        
        assignment = cursor.fetchone()
        if assignment and assignment['is_used']:
            return {'success': False, 'message': 'You have already used this coupon'}
        
        # Check course/institute applicability
        if coupon['applicable_courses']:
            applicable_courses = json.loads(coupon['applicable_courses'])
            if course_id not in applicable_courses:
                return {'success': False, 'message': 'Coupon is not applicable to this course'}
        
        # Calculate discount
        discount_applied = 0.0
        coupon_type = coupon['coupon_type']
        
        if coupon_type == 'balance':
            available_balance = float(coupon['balance'])
            discount_applied = min(available_balance, original_price)
        
        elif coupon_type == 'percentage':
            discount_percentage = float(coupon['discount_value'])
            discount_applied = (original_price * discount_percentage) / 100
            
            if coupon['max_discount_amount']:
                discount_applied = min(discount_applied, float(coupon['max_discount_amount']))
        
        elif coupon_type == 'fixed':
            discount_applied = min(float(coupon['discount_value']), original_price)
        
        final_price = max(0, original_price - discount_applied)
        
        return {
            'success': True,
            'coupon_id': coupon['id'],
            'coupon_type': coupon_type,
            'discount_applied': discount_applied,
            'final_price': final_price,
            'message': f'Coupon applied! You saved NPR {discount_applied:.2f}'
        }
        
    except Exception as e:
        logger.error(f"Error validating coupon: {str(e)}")
        return {'success': False, 'message': 'Error validating coupon'}

def _record_coupon_usage(cursor, coupon_id, user_id, course_id, enrollment_id, amount_used, original_price, final_price):
    """Record coupon usage in history"""
    cursor.execute("""
        INSERT INTO coupon_usage_history 
        (coupon_id, user_id, course_id, enrollment_id, amount_used, original_price, final_price, discount_applied)
        VALUES (%s, %s, %s, %s, %s, %s, %s, %s)
    """, (coupon_id, user_id, course_id, enrollment_id, amount_used, original_price, final_price, amount_used))
import json



logger = logging.getLogger(__name__)

payment_bp = Blueprint('payment', __name__, url_prefix='/api/payment')

# Configure upload folder
UPLOAD_FOLDER = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'uploads', 'payment_screenshots')
ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif', 'webp'}

def allowed_file(filename):
    return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

def ensure_upload_folder():
    if not os.path.exists(UPLOAD_FOLDER):
        os.makedirs(UPLOAD_FOLDER)


@payment_bp.route('/methods', methods=['GET'])
@require_api_key
def get_payment_methods():
    """
    Get all active payment methods with QR codes
    """
    conn = None
    cursor = None
    try:
        conn = get_cached_connection()
        if not conn:
            return create_error_response("Database connection failed", 500)
        
        cursor = conn.cursor(dictionary=True)
        
        cursor.execute("""
            SELECT 
                id,
                name,
                type,
                account_name,
                account_number,
                qr_code_url,
                instructions,
                display_order
            FROM payment_methods
            WHERE is_active = 1
            ORDER BY display_order ASC
        """)
        
        methods = cursor.fetchall()
        
        payment_methods_data = {
            'payment_methods': methods
        }
        return format_api_response(
            data=payment_methods_data,
            message="Payment methods retrieved successfully",
            include_legacy_fields=payment_methods_data
        )
        
    except Exception as e:
        logger.error(f"Error fetching payment methods: {str(e)}")
        return create_error_response(f"Failed to fetch payment methods: {str(e)}", 500)
    finally:
        if cursor:
            cursor.close()
        if conn:
            conn.close()


@payment_bp.route('/submit', methods=['POST'])
@require_api_key
@require_auth
def submit_payment():
    """
    Submit payment screenshot for verification
    Expects multipart/form-data with:
    - enrollment_id: int (optional if package_id provided)
    - package_id: int (optional if enrollment_id provided)
    - payment_method_id: int
    - amount: float
    - screenshot: file
    - transaction_id: string (optional)
    - notes: string (optional)
    """
    conn = None
    cursor = None
    try:
        user_id = g.current_user_id
        
        # Get form data
        enrollment_id = request.form.get('enrollment_id')
        package_id = request.form.get('package_id')
        payment_method_id = request.form.get('payment_method_id')
        amount = request.form.get('amount')
        transaction_id = request.form.get('transaction_id')
        notes = request.form.get('notes')
        coupon_code = request.form.get('coupon_code')
        
        # Validate required fields
        if not payment_method_id or not amount:
             return create_error_response("payment_method_id and amount are required", 400)
             
        if not enrollment_id and not package_id:
             return create_error_response("Either enrollment_id or package_id is required", 400)
             
        # Check for screenshot file
        if 'screenshot' not in request.files:
            return create_error_response("Payment screenshot is required", 400)
        
        file = request.files['screenshot']
        if file.filename == '':
            return create_error_response("No file selected", 400)
        
        if not allowed_file(file.filename):
            return create_error_response("Invalid file type. Allowed: png, jpg, jpeg, gif, webp", 400)
        
        conn = get_cached_connection()
        if not conn:
            return create_error_response("Database connection failed", 500)
        
        cursor = conn.cursor(dictionary=True)
        
        submission_amount = amount
        
        # Scenario A: Course Enrollment
        if enrollment_id:
            # Verify enrollment belongs to user and is pending payment
            cursor.execute("""
                SELECT e.id, e.payment_status, e.course_id, c.price, c.final_price
                FROM enrollments e
                JOIN courses c ON e.course_id = c.id
                WHERE e.id = %s AND e.user_id = %s
            """, (enrollment_id, user_id))
            
            enrollment = cursor.fetchone()
            if not enrollment:
                return create_error_response("Enrollment not found or access denied", 404)
            
            if enrollment['payment_status'] not in ('pending', 'whatsapp'):
                return create_error_response("Payment already processed for this enrollment", 400)
            
            # Check for existing pending submission
            cursor.execute("""
                SELECT id FROM payment_submissions
                WHERE enrollment_id = %s AND status = 'pending'
            """, (enrollment_id,))
            
            if cursor.fetchone():
                return create_error_response("A payment submission is already pending verification", 400)
                
            # Handle coupons (existing logic) ...
            if coupon_code:
                 # (Use existing logic for coupon validation - simplified here for brevity, assume helper handles it)
                 course_id = enrollment['course_id']
                 original_price = float(enrollment['final_price'])
                 coupon_result = _validate_and_apply_coupon_logic(cursor, user_id, course_id, coupon_code, original_price)
                 
                 if coupon_result['success']:
                     # Update enrollment
                     new_price = coupon_result['final_price']
                     submission_amount = new_price # Override amount
                     cursor.execute("UPDATE enrollments SET payment_amount = %s, coupon_id = %s, discount_applied = %s WHERE id = %s", 
                         (new_price, coupon_result['coupon_id'], coupon_result['discount_applied'], enrollment_id))
                     _record_coupon_usage(cursor, coupon_result['coupon_id'], user_id, course_id, enrollment_id, coupon_result['discount_applied'], original_price, new_price)
                 else:
                     return create_error_response(f"Invalid coupon: {coupon_result['message']}", 400)

        # Scenario B: Token Package
        elif package_id:
            # Verify package exists
            cursor.execute("""
                SELECT id, plan_name, price_monthly 
                FROM subscription_plans 
                WHERE id = %s AND is_active = TRUE
            """, (package_id,))
            
            package = cursor.fetchone()
            if not package:
                return create_error_response("Invalid or inactive package", 400)
                
            # Check price rough match? (Optional, maybe skip strictly)
            
            # Check for existing pending submission for this user/package?
            # Maybe allowed to buy multiple times, but let's prevent spam
            cursor.execute("""
                SELECT id FROM payment_submissions
                WHERE user_id = %s AND package_id = %s AND status = 'pending'
            """, (user_id, package_id))
             # Just warn or allow? Let's allow but maybe rate limit. For now allow.
        
        # Verify payment method exists
        cursor.execute("SELECT id FROM payment_methods WHERE id = %s AND is_active = 1", (payment_method_id,))
        if not cursor.fetchone():
            return create_error_response("Invalid payment method", 400)
        
        # Save screenshot
        ensure_upload_folder()
        filename = secure_filename(file.filename)
        unique_filename = f"{uuid.uuid4()}_{filename}"
        file_path = os.path.join(UPLOAD_FOLDER, unique_filename)
        file.save(file_path)
        screenshot_url = f"/uploads/payment_screenshots/{unique_filename}"
        
        # Insert submission
        cursor.execute("""
            INSERT INTO payment_submissions
            (user_id, enrollment_id, package_id, payment_method_id, amount, screenshot_url, transaction_id, notes, status)
            VALUES (%s, %s, %s, %s, %s, %s, %s, %s, 'pending')
        """, (user_id, enrollment_id, package_id, payment_method_id, submission_amount, screenshot_url, transaction_id, notes))
        
        submission_id = cursor.lastrowid
        conn.commit()
        
        return format_api_response(
            data={'submission_id': submission_id, 'status': 'pending'},
            message="Payment submitted for verification"
        )
        
    except Exception as e:
        if conn: conn.rollback()
        logger.error(f"Error submitting payment: {str(e)}")
        import traceback
        traceback.print_exc()
        return create_error_response(f"Failed to submit payment: {str(e)}", 500)
    finally:
        if cursor: cursor.close()
        if conn: conn.close()


@payment_bp.route('/status/<int:enrollment_id>', methods=['GET'])
@require_api_key
@require_auth
def get_payment_status(enrollment_id):
    """
    Check payment verification status for an enrollment
    """
    conn = None
    cursor = None
    try:
        user_id = g.current_user_id
        
        conn = get_cached_connection()
        if not conn:
            return create_error_response("Database connection failed", 500)
        
        cursor = conn.cursor(dictionary=True)
        
        # Verify enrollment belongs to user
        cursor.execute("""
            SELECT id FROM enrollments WHERE id = %s AND user_id = %s
        """, (enrollment_id, user_id))
        
        if not cursor.fetchone():
            return create_error_response("Enrollment not found or access denied", 404)
        
        # Get latest payment submission
        cursor.execute("""
            SELECT 
                ps.id,
                ps.status,
                ps.submitted_at,
                ps.verified_at,
                ps.rejection_reason,
                pm.name as payment_method_name
            FROM payment_submissions ps
            JOIN payment_methods pm ON ps.payment_method_id = pm.id
            WHERE ps.enrollment_id = %s
            ORDER BY ps.submitted_at DESC
            LIMIT 1
        """, (enrollment_id,))
        
        submission = cursor.fetchone()
        
        if not submission:
            status_data = {
                'has_submission': False,
                'status': None
            }
        else:
            status_data = {
                'has_submission': True,
                'submission_id': submission['id'],
                'status': submission['status'],
                'payment_method': submission['payment_method_name'],
                'submitted_at': submission['submitted_at'].isoformat() if submission['submitted_at'] else None,
                'verified_at': submission['verified_at'].isoformat() if submission['verified_at'] else None,
                'rejection_reason': submission['rejection_reason']
            }
        
        return format_api_response(
            data=status_data,
            message="Payment status retrieved",
            include_legacy_fields=status_data
        )
        
    except Exception as e:
        logger.error(f"Error fetching payment status: {str(e)}")
        return create_error_response(f"Failed to fetch payment status: {str(e)}", 500)
    finally:
        if cursor:
            cursor.close()
        if conn:
            conn.close()


@payment_bp.route('/verify/<int:submission_id>', methods=['POST'])
@require_api_key
@require_auth
def verify_payment(submission_id):
    """
    Admin endpoint to verify or reject a payment submission
    Requires admin role
    """
    conn = None
    cursor = None
    try:
        admin_id = g.current_user_id
        data = request.get_json()
        
        if not data:
            return create_error_response("Request data is required", 400)
        
        action = data.get('action')  # 'verify' or 'reject'
        rejection_reason = data.get('rejection_reason')
        
        if action not in ('verify', 'reject'):
            return create_error_response("Action must be 'verify' or 'reject'", 400)
        
        if action == 'reject' and not rejection_reason:
            return create_error_response("Rejection reason is required", 400)
        
        conn = get_cached_connection()
        if not conn:
            return create_error_response("Database connection failed", 500)
        
        cursor = conn.cursor(dictionary=True)
        
        # Get submission details
        cursor.execute("""
            SELECT ps.*
            FROM payment_submissions ps
            WHERE ps.id = %s AND ps.status = 'pending'
        """, (submission_id,))
        
        submission = cursor.fetchone()
        if not submission:
            return create_error_response("Pending submission not found", 404)
        
        user_id = submission['user_id']
        enrollment_id = submission['enrollment_id']
        package_id = submission['package_id']
        
        if action == 'verify':
            # Update submission status
            cursor.execute("""
                UPDATE payment_submissions
                SET status = 'verified', verified_at = NOW(), verified_by = %s
                WHERE id = %s
            """, (admin_id, submission_id))
            
            # Scenario A: Enrollment
            if enrollment_id:
                cursor.execute("""
                    UPDATE enrollments
                    SET payment_status = 'paid'
                    WHERE id = %s
                """, (enrollment_id,))
            
            # Scenario B: Token Package
            elif package_id:
                # Grant tokens!
                from services.token_manager import TokenManager
                
                # Get package info
                cursor.execute("SELECT plan_name, benefits, price_monthly FROM subscription_plans WHERE id = %s", (package_id,))
                pkg = cursor.fetchone()
                
                if pkg:
                    import json
                    benefits = pkg.get('benefits', {})
                    if isinstance(benefits, str): benefits = json.loads(benefits)
                    ai_benefits = benefits.get('ai_tokens', {})
                    tokens_to_add = ai_benefits.get('monthly_allowance', 0)
                    
                    # Call TokenManager to add tokens
                    TokenManager.add_tokens(
                         user_id=user_id,
                         amount=float(tokens_to_add),
                         transaction_type='purchase',
                         purchase_package_id=package_id,
                         payment_id=f"SUB-{submission_id}",
                         payment_method="QR/Manual",
                         payment_amount=float(submission['amount']),
                         notes=f"Verified payment for {pkg['plan_name']}"
                    )
            
            message = "Payment verified successfully"
        else:
            # Reject payment
            cursor.execute("""
                UPDATE payment_submissions
                SET status = 'rejected', rejection_reason = %s, verified_at = NOW(), verified_by = %s
                WHERE id = %s
            """, (rejection_reason, admin_id, submission_id))
            
            message = "Payment rejected"
        
        conn.commit()
        
        return format_api_response(
            data={'submission_id': submission_id, 'status': 'verified' if action == 'verify' else 'rejected'},
            message=message,
            include_legacy_fields={'success': True}
        )
        
    except Exception as e:
        if conn: conn.rollback()
        logger.error(f"Error verifying payment: {str(e)}")
        return create_error_response(f"Failed to verify payment: {str(e)}", 500)
    finally:
        if cursor: cursor.close()
        if conn: conn.close()


@payment_bp.route('/admin/submissions', methods=['GET'])
@require_api_key
@require_auth
def get_admin_submissions():
    """
    Admin endpoint to get all payment submissions
    Query params:
    - status: 'pending', 'verified', 'rejected', or 'all'
    """
    conn = None
    cursor = None
    try:
        # TODO: Add admin role check here
        
        status_filter = request.args.get('status', 'pending')
        
        conn = get_cached_connection()
        if not conn:
            return create_error_response("Database connection failed", 500)
        
        cursor = conn.cursor(dictionary=True)
        
        # Build query based on status filter
        if status_filter == 'all':
            status_condition = ""
            params = ()
        else:
            status_condition = "WHERE ps.status = %s"
            params = (status_filter,)
        
        cursor.execute(f"""
            SELECT 
                ps.id,
                ps.user_id,
                u.full_name as user_name,
                u.email as user_email,
                ps.enrollment_id,
                c.title as course_title,
                pm.name as payment_method_name,
                ps.amount,
                ps.screenshot_url,
                ps.transaction_id,
                ps.notes,
                ps.status,
                ps.rejection_reason,
                ps.submitted_at,
                ps.verified_at
            FROM payment_submissions ps
            JOIN users u ON ps.user_id = u.id
            JOIN enrollments e ON ps.enrollment_id = e.id
            JOIN courses c ON e.course_id = c.id
            JOIN payment_methods pm ON ps.payment_method_id = pm.id
            {status_condition}
            ORDER BY ps.submitted_at DESC
            LIMIT 100
        """, params)
        
        submissions = cursor.fetchall()
        
        # Convert datetime objects to ISO strings
        for sub in submissions:
            if sub.get('submitted_at'):
                sub['submitted_at'] = sub['submitted_at'].isoformat()
            if sub.get('verified_at'):
                sub['verified_at'] = sub['verified_at'].isoformat()
        
        return format_api_response(
            data={'submissions': submissions, 'count': len(submissions)},
            message=f"Found {len(submissions)} submissions",
            include_legacy_fields={'submissions': submissions}
        )
        
    except Exception as e:
        logger.error(f"Error fetching admin submissions: {str(e)}")
        return create_error_response(f"Failed to fetch submissions: {str(e)}", 500)
    finally:
        if cursor:
            cursor.close()
        if conn:
            conn.close()


@payment_bp.route('/my-transactions', methods=['GET'])
@require_api_key
@require_auth
def get_my_transactions():
    """
    Get current user's payment transactions history
    Shows all payment submissions including pending, verified, and rejected
    """
    conn = None
    cursor = None
    try:
        user_id = g.current_user_id
        
        conn = get_cached_connection()
        if not conn:
            return create_error_response("Database connection failed", 500)
        
        cursor = conn.cursor(dictionary=True)
        
        cursor.execute("""
            SELECT 
                ps.id,
                ps.enrollment_id,
                COALESCE(c.title, 'Unknown Course') as course_title,
                c.image_url as course_image,
                pm.name as payment_method_name,
                pm.type as payment_method_type,
                ps.amount,
                ps.screenshot_url,
                ps.transaction_id,
                ps.notes,
                ps.status,
                ps.rejection_reason,
                ps.submitted_at,
                ps.verified_at,
                e.payment_status as enrollment_status
            FROM payment_submissions ps
            LEFT JOIN enrollments e ON ps.enrollment_id = e.id
            LEFT JOIN courses c ON e.course_id = c.id
            LEFT JOIN payment_methods pm ON ps.payment_method_id = pm.id
            WHERE ps.user_id = %s
            ORDER BY ps.submitted_at DESC
        """, (user_id,))
        
        transactions = cursor.fetchall()
        
        # Convert datetime objects and count by status
        pending_count = 0
        verified_count = 0
        rejected_count = 0
        
        for txn in transactions:
            if txn.get('submitted_at'):
                txn['submitted_at'] = txn['submitted_at'].isoformat()
            if txn.get('verified_at'):
                txn['verified_at'] = txn['verified_at'].isoformat()
            
            if txn['status'] == 'pending':
                pending_count += 1
            elif txn['status'] == 'verified':
                verified_count += 1
            elif txn['status'] == 'rejected':
                rejected_count += 1
        
        return format_api_response(
            data={
                'transactions': transactions,
                'total': len(transactions),
                'pending': pending_count,
                'verified': verified_count,
                'rejected': rejected_count
            },
            message=f"Found {len(transactions)} transactions",
            include_legacy_fields={'transactions': transactions}
        )
        
    except Exception as e:
        logger.error(f"Error fetching user transactions: {str(e)}")
        return create_error_response(f"Failed to fetch transactions: {str(e)}", 500)
    finally:
        if cursor:
            cursor.close()
        if conn:
            conn.close()


