// const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY); // Lazy load inside functions to avoid crash if env is missing

const db = require('../db');
const { sendSubscriptionUpgradedEmail, sendAdminUpgradeNotification } = require('../utils/emailService');

// Helper to get settings from DB
const getSystemSetting = async (key) => {
    try {
        const result = await db.query("SELECT value FROM system_settings WHERE `key` = ?", [key]);
        return result.rows.length > 0 ? result.rows[0].value : null;
    } catch (error) {
        console.error(`Error fetching setting ${key}:`, error);
        return null;
    }
};

/**
 * Initiates a Stripe Checkout Session.
 * 
 * Capabilities:
 * - Handles both Individual and Organization subscription flows.
 * - Applies eligible discounts (e.g. Student Trial) automatically based on user attributes.
 * - Securely manages Customer ID creation/retrieval.
 * - Redirects to Stripe hosted payment page.
 * 
 * @route POST /api/payments/create-checkout-session
 * @access Private
 */
exports.createCheckoutSession = async (req, res) => {
    // ... existing logic or placeholder ...
    // Assuming this is already implemented or not the focus right now.
    // If not, I'll add a basic implementation.
    try {
        const { priceId } = req.body;
        const userId = req.user.id;
        const userEmail = req.user.email;

        // Determine origin - Force main domain for production to avoid subdomain confusion
        // Determine origin
        const origin = process.env.CLIENT_ORIGIN || req.headers.origin || 'http://localhost:5173';

        // Fetch stripe secret from DB if not in env
        let stripeKey = process.env.STRIPE_SECRET_KEY;
        const dbStripeKey = await getSystemSetting('stripe_secret_key');
        if (dbStripeKey) {
            stripeKey = dbStripeKey;
            // Handle double quotes from JSON storage
            try {
                if (stripeKey.startsWith('"')) stripeKey = JSON.parse(stripeKey);
            } catch (e) {
                // ignore
            }
        }

        if (!stripeKey || stripeKey.includes('sk_test_...')) {
            return res.status(500).json({ message: 'Stripe secret key not configured or invalid' });
        }

        const stripeInstance = require('stripe')(stripeKey);

        // Check if user has a customer_id
        const userResult = await db.query('SELECT customer_id FROM users WHERE id = ?', [userId]);
        const existingCustomerId = userResult.rows[0]?.customer_id;

        const sessionConfig = {
            mode: 'subscription',
            // Default to dashboard settings for payment methods (removes restriction to just 'card')
            // payment_method_types: ['card'], 
            line_items: [
                {
                    price: priceId,
                    quantity: req.body.quantity || 1,
                },
            ],
            metadata: {
                userId: userId.toString(),
            },
            success_url: `${origin}/dashboard?session_id={CHECKOUT_SESSION_ID}`,
            cancel_url: `${origin}/pricing`,
        };

        // STUDENT PLAN LOGIC: Check for .edu email OR 'is_student' flag OR Whitelisted Domain AND ensure it's the Monthly plan
        // We do not want to give 3 months free on a Yearly subscription (unless explicitly desired, but user requested restriction)
        
        let isStudent = userEmail.toLowerCase().endsWith('.edu') || req.user.is_student;

        // Check Whitelisted Domains if not already identified
        if (!isStudent) {
            const domain = userEmail.split('@')[1];
            if (domain) {
                const domainCheck = await db.query(
                    'SELECT 1 FROM student_domains WHERE domain = ? OR domain = ?', 
                    [domain.toLowerCase(), `@${domain.toLowerCase()}`]
                );
                if (domainCheck.rows.length > 0) {
                    isStudent = true;
                    console.log(`Student identified via whitelist (${userEmail})`);
                }
            }
        }

        if (isStudent) {
            // Check if the priceId matches the Monthly Price ID
            // We need to fetch the config or hardcode/check dynamic IDs. 
            // Better approach: We passed priceId. We can compare it if we have the config loaded or stored.
            // However, typically the client sends the priceId. 
            // Let's assume we want to apply it ONLY if it's NOT the yearly price.
            // But we don't strictly know which is which without checking DB/Config.
            // SIMPLER: Retrieve the plan interval from Stripe or assume we pass 'monthly' context.
            // FASTER FIX: We will look up the price object from Stripe first to confirm interval.

            const price = await stripeInstance.prices.retrieve(priceId);
            if (price.recurring.interval === 'month') {
                console.log(`Student identified (${userEmail}, is_student=${req.user.is_student}) on MONTHLY plan. Applying 90-day trial.`);
                sessionConfig.subscription_data = {
                    trial_period_days: 90
                };
            } else {
                console.log(`Student identified (${userEmail}) but plan is ${price.recurring.interval}. GP trial NOT applied.`);
            }
        }

        // If we have an existing customer ID, use it to avoid duplicates
        if (existingCustomerId) {
            sessionConfig.customer = existingCustomerId;
            sessionConfig.customer_update = {
                name: 'auto',
                address: 'auto'
            };
        } else {
            // Otherwise prepopulate email
            sessionConfig.customer_email = userEmail;
        }

        const session = await stripeInstance.checkout.sessions.create(sessionConfig);

        res.json({ sessionId: session.id, url: session.url });
    } catch (error) {
        console.error('Error creating checkout session:', error);
        res.status(500).json({ message: 'Stripe Error: ' + error.message });
    }
};

/**
 * Handles asynchronous events sent by Stripe.
 * 
 * Capabilities:
 * - Verifies webhook signature to prevent spoofing.
 * - Processes:
 *   - 'checkout.session.completed': Activates subscription/trial
 *   - 'customer.subscription.updated': Handles renewals/cancellations
 *   - 'customer.subscription.deleted': Downgrades user to free tier
 * 
 * @route POST /api/payments/webhook
 * @access Public (Signature Verified)
 */
exports.handlePaymentWebhook = async (req, res) => {
    const sig = req.headers['stripe-signature'];
    let event;

    try {
        // 1. Get Webhook Secret
        let webhookSecret = process.env.STRIPE_WEBHOOK_SECRET;
        const dbWebhookSecret = await getSystemSetting('stripe_webhook_secret');
        if (dbWebhookSecret) {
            webhookSecret = dbWebhookSecret;
            // Strip quotes if present
            if (typeof webhookSecret === 'string' && webhookSecret.startsWith('"')) {
                try { webhookSecret = JSON.parse(webhookSecret); } catch (e) { }
            }
        }

        // 2. Get Stripe Secret Key (needed to init Stripe instance)
        let stripeKey = process.env.STRIPE_SECRET_KEY;
        const dbStripeKey = await getSystemSetting('stripe_secret_key');
        if (dbStripeKey) {
            stripeKey = dbStripeKey;
            // Strip quotes if present
            if (typeof stripeKey === 'string' && stripeKey.startsWith('"')) {
                try { stripeKey = JSON.parse(stripeKey); } catch (e) { }
            }
        }

        if (!stripeKey) {
            console.error('Stripe secret key not configured, skipping webhook');
            return res.status(500).send('Stripe key missing');
        }

        const stripeInstance = require('stripe')(stripeKey);

        // 3. Verify Signature
        event = stripeInstance.webhooks.constructEvent(req.body, sig, webhookSecret);
    } catch (err) {
        console.error(`Webhook Error Details: ${err.message}`);
        // Log start of body to see if it's JSON or Buffer (for debugging)
        console.error(`Received Body Type: ${typeof req.body}, IsBuffer: ${Buffer.isBuffer(req.body)}`);
        return res.status(400).send(`Webhook Error: ${err.message}`);
    }

    // 4. Handle the event
    try {
        switch (event.type) {
            case 'invoice.payment_succeeded':
                const invoice = event.data.object;
                await handlePaymentSucceeded(invoice);
                break;
            case 'invoice.payment_failed':
                const invoiceFailed = event.data.object;
                await handlePaymentFailed(invoiceFailed);
                break;
            case 'customer.subscription.deleted':
                const subscription = event.data.object;
                await handleSubscriptionDeleted(subscription);
                break;
            default:
                console.log(`Unhandled event type ${event.type}`);
        }
    } catch (error) {
        console.error('Error handling webhook event:', error);
        return res.status(500).send('Server Error');
    }

    res.json({ received: true });
};

async function handlePaymentSucceeded(invoice) {
    const customerEmail = invoice.customer_email;
    const stripeCustomerId = invoice.customer;
    const subscriptionId = invoice.subscription;

    console.log(`Processing payment success for ${customerEmail}`);

    const userResult = await db.query('SELECT * FROM users WHERE email = ?', [customerEmail]);
    if (userResult.rows.length === 0) {
        console.error(`User not found for email ${customerEmail}`);
        return;
    }
    const user = userResult.rows[0];

    // Determine plan type from invoice lines
    let interval = 'monthly';
    if (invoice.lines && invoice.lines.data.length > 0) {
        const lineItem = invoice.lines.data[0];
        if (lineItem.price && lineItem.price.recurring && lineItem.price.recurring.interval === 'year') {
            interval = 'yearly';
        }
    }

    // Calculate renewal date - use the period_end from Stripe if available for better accuracy
    let renewalDate = new Date();
    if (invoice.lines && invoice.lines.data.length > 0) {
        const lineItem = invoice.lines.data[0];
        if (lineItem.period && lineItem.period.end) {
            renewalDate = new Date(lineItem.period.end * 1000);
        } else {
            // Fallback calculation
            if (interval === 'yearly') {
                renewalDate.setFullYear(renewalDate.getFullYear() + 1);
            } else {
                renewalDate.setMonth(renewalDate.getMonth() + 1);
            }
        }
    }

    // Determine if this is a Monthly to Yearly upgrade
    const isMonthlyToYearlyUpgrade = (user.subscription_plan === 'monthly' && interval === 'yearly');
    const isUpgrade = isMonthlyToYearlyUpgrade || (user.role === 'pro' && user.subscription_plan !== interval);

    // Update user: plan, end_date, renewal_date, STATUS, IDs, and ROLE
    await db.query(
        "UPDATE users SET subscription_plan = ?, subscription_end_date = ?, renewal_date = ?, subscription_status = 'active', customer_id = ?, subscription_id = ?, role = ? WHERE id = ?",
        [interval, renewalDate, renewalDate, stripeCustomerId, subscriptionId, newRole, user.id]
    );

    // Send branded email to user
    await sendSubscriptionUpgradedEmail(user.email, user.name, interval, isUpgrade);

    // Send notification to Admin
    await sendAdminUpgradeNotification(user.email, user.name, interval, isUpgrade);

    // ============================================
    // REFERRAL SYSTEM: 1 MONTH PRO REWARD
    // ============================================
    try {
        if (user.referred_by) {
            // Check if this referral hasn't been rewarded yet
            const refCheck = await db.query(
                `SELECT id, status FROM referrals WHERE referrer_id = ? AND referee_id = ? AND status != 'subscribed'`,
                [user.referred_by, user.id]
            );
            
            if (refCheck.rows.length > 0) {
                const referralRecordId = refCheck.rows[0].id;
                
                // 1. Get the referrer to update their subscription
                const referrerResult = await db.query('SELECT id, email, name, role, subscription_end_date FROM users WHERE id = ?', [user.referred_by]);
                if (referrerResult.rows.length > 0) {
                    const referrer = referrerResult.rows[0];
                    
                    // Add 30 days to their subscription
                    let newEndDate = referrer.subscription_end_date ? new Date(referrer.subscription_end_date) : new Date();
                    // If they had no active sub or it was in the past, start from today
                    if (newEndDate < new Date()) newEndDate = new Date();
                    newEndDate.setDate(newEndDate.getDate() + 30);
                    
                    // If they were 'normal', upgrade them to 'pro'
                    const referrerNewRole = referrer.role === 'normal' ? 'pro' : referrer.role;
                    
                    // Update referrer in DB
                    await db.query(`
                        UPDATE users 
                        SET subscription_end_date = ?, 
                            renewal_date = ?, 
                            subscription_plan = COALESCE(NULLIF(subscription_plan, 'free'), 'monthly'),
                            subscription_status = 'active',
                            role = ? 
                        WHERE id = ?`,
                        [newEndDate, newEndDate, referrerNewRole, referrer.id]
                    );
                    
                    // 2. Mark referral as completed/subscribed
                    await db.query(`UPDATE referrals SET status = 'subscribed', reward_earned = TRUE WHERE id = ?`, [referralRecordId]);
                    
                    // 3. Send email to referrer
                    const { sendReferralRewardEmail } = require('../utils/emailService');
                    if (typeof sendReferralRewardEmail === 'function') {
                        await sendReferralRewardEmail(referrer.email, referrer.name, user.name);
                    }
                }
            }
        }
    } catch (refError) {
        console.error('Error processing referral reward:', refError);
        // Do not throw, allow the main payment webhook to succeed
    }
}

async function handlePaymentFailed(invoice) {
    const customerEmail = invoice.customer_email;
    console.log(`Processing payment failure for ${customerEmail}`);

    const userResult = await db.query('SELECT * FROM users WHERE email = ?', [customerEmail]);
    if (userResult.rows.length === 0) return;
    const user = userResult.rows[0];

    // Downgrade to free AND normal role if they were pro
    let newRole = user.role;
    if (newRole === 'pro') {
        newRole = 'normal';
    }

    await db.query("UPDATE users SET subscription_plan = 'free', subscription_end_date = NULL, role = ? WHERE id = ?", [newRole, user.id]);
}

async function handleSubscriptionDeleted(subscription) {
    console.log('Subscription deleted webhook received:', subscription.id);
    
    try {
        // 1. Find user by subscription_id
        let userResult = await db.query('SELECT id, role, email FROM users WHERE subscription_id = ?', [subscription.id]);
        
        // 2. Fallback: Find user by customer_id if subscription_id not found (unlikely but safer)
        if (userResult.rows.length === 0 && subscription.customer) {
            userResult = await db.query('SELECT id, role, email FROM users WHERE customer_id = ?', [subscription.customer]);
        }

        if (userResult.rows.length > 0) {
            const user = userResult.rows[0];
            
            // Determine new role (downgrade to normal if pro)
            let newRole = user.role;
            if (newRole === 'pro') {
                newRole = 'normal';
            }

            // Update user record: back to free tier
            await db.query(
                `UPDATE users SET 
                    subscription_plan = 'free', 
                    subscription_id = NULL,
                    subscription_status = 'canceled',
                    renewal_date = NULL,
                    role = ?
                WHERE id = ?`,
                [newRole, user.id]
            );
            
            console.log(`User ${user.email} (ID: ${user.id}) downgraded due to subscription deletion.`);
        } else {
            console.warn(`Could not find user for deleted subscription: ${subscription.id} (Customer: ${subscription.customer})`);
        }
    } catch (error) {
        console.error('Error handling subscription deletion webhook:', error);
    }
}

// ============================================
// EMBEDDED STRIPE ELEMENTS PAYMENT ENDPOINTS
// ============================================

// Helper to get Stripe instance
const getStripeInstance = async () => {
    let stripeKey = process.env.STRIPE_SECRET_KEY;
    const dbStripeKey = await getSystemSetting('stripe_secret_key');
    if (dbStripeKey) {
        stripeKey = dbStripeKey;
        if (typeof stripeKey === 'string' && stripeKey.startsWith('"')) {
            try { stripeKey = JSON.parse(stripeKey); } catch (e) { }
        }
    }

    if (!stripeKey || stripeKey.includes('sk_test_...')) {
        throw new Error('Stripe secret key not configured');
    }

    return require('stripe')(stripeKey);
};

// Create a subscription with PaymentIntent for embedded checkout
exports.createSubscription = async (req, res) => {
    try {
        const { priceId } = req.body;
        const userId = req.user.id;
        const userEmail = req.user.email;
        const userName = req.user.name;

        const stripe = await getStripeInstance();

        // Step 1: Find or create a Stripe customer
        let customerId;

        // Check if user already has a customer_id
        const userResult = await db.query('SELECT customer_id FROM users WHERE id = ?', [userId]);
        customerId = userResult.rows[0]?.customer_id;

        if (!customerId) {
            // Create a new customer
            const customer = await stripe.customers.create({
                email: userEmail,
                name: userName,
                metadata: {
                    userId: userId.toString()
                }
            });
            customerId = customer.id;

            // Store customer_id for future use
            await db.query('UPDATE users SET customer_id = ? WHERE id = ?', [customerId, userId]);
        }

        // Step 2: Create the subscription
        console.log('Creating subscription with priceId:', priceId, 'customerId:', customerId);

        const subscription = await stripe.subscriptions.create({
            customer: customerId,
            items: [{ price: priceId }],
            payment_behavior: 'default_incomplete',
            payment_settings: {
                save_default_payment_method: 'on_subscription'
            },
            expand: ['latest_invoice.payment_intent'],
            trial_period_days: 0, // Force no trial - payment required immediately
            metadata: {
                userId: userId.toString()
            }
        });

        console.log('Subscription created:', subscription.id);
        console.log('Latest invoice:', subscription.latest_invoice?.id);
        console.log('Payment intent:', subscription.latest_invoice?.payment_intent?.id);

        // Get the client secret from the payment intent
        if (!subscription.latest_invoice?.payment_intent?.client_secret) {
            console.error('No payment intent client_secret found. Subscription status:', subscription.status);
            console.error('Invoice status:', subscription.latest_invoice?.status);
            return res.status(500).json({
                message: 'Subscription created but no payment required. This may be a free trial or $0 price. Check Stripe price configuration.'
            });
        }

        const clientSecret = subscription.latest_invoice.payment_intent.client_secret;

        res.json({
            subscriptionId: subscription.id,
            clientSecret: clientSecret
        });

    } catch (error) {
        console.error('Error creating subscription:', error);
        res.status(500).json({ message: 'Failed to create subscription: ' + error.message });
    }
};

// Confirm subscription after successful payment
exports.confirmSubscription = async (req, res) => {
    try {
        const { subscriptionId } = req.body;
        const userId = req.user.id;

        const stripe = await getStripeInstance();

        // Retrieve subscription to verify status
        const subscription = await stripe.subscriptions.retrieve(subscriptionId);

        if (subscription.status === 'active' || subscription.status === 'trialing') {
            // Determine plan type from price interval
            const priceId = subscription.items.data[0]?.price?.id;
            let planType = 'monthly';

            // Check if it's yearly by fetching price details
            try {
                const price = await stripe.prices.retrieve(priceId);
                if (price.recurring?.interval === 'year') {
                    planType = 'yearly';
                }
            } catch (e) {
                console.log('Could not determine price interval, defaulting to monthly');
            }

            // Calculate renewal date
            const renewalDate = new Date(subscription.current_period_end * 1000);

            // Determine new role
            const userRes = await db.query("SELECT role FROM users WHERE id = ?", [userId]);
            let userRole = userRes.rows[0]?.role;
            if (userRole === 'normal') userRole = 'pro';

            // Determine if this is a Plan Upgrade
            const isUpgrade = (userRole === 'pro' && planType === 'yearly');

            // Update user subscription
            await db.query(
                `UPDATE users SET 
                    subscription_plan = ?, 
                    subscription_id = ?,
                    renewal_date = ?,
                    subscription_end_date = ?,
                    subscription_status = 'active',
                    role = ?
                WHERE id = ?`,
                [planType, subscriptionId, renewalDate, renewalDate, userRole, userId]
            );

            // Send confirmation branded email to user
            const userResult = await db.query('SELECT email, name FROM users WHERE id = ?', [userId]);
            const user = userResult.rows[0];
            await sendSubscriptionUpgradedEmail(user.email, user.name, planType, isUpgrade);

            // Send notification to Admin
            await sendAdminUpgradeNotification(user.email, user.name, planType, isUpgrade);

            res.json({
                success: true,
                message: 'Subscription activated',
                subscription_plan: planType,
                renewal_date: renewalDate
            });
        } else {
            res.status(400).json({
                success: false,
                message: `Subscription status is ${subscription.status}, not active`
            });
        }

    } catch (error) {
        console.error('Error confirming subscription:', error);
        res.status(500).json({ message: 'Failed to confirm subscription: ' + error.message });
    }
};

// Cancel a subscription
exports.cancelSubscription = async (req, res) => {
    try {
        const userId = req.user.id;

        // Get user's subscription ID
        const userResult = await db.query('SELECT subscription_id, subscription_plan FROM users WHERE id = ?', [userId]);
        const user = userResult.rows[0];

        if (!user?.subscription_id) {
            return res.status(400).json({ message: 'No active subscription found' });
        }

        const stripe = await getStripeInstance();

        // Cancel the subscription at period end (user keeps access until renewal date)
        const subscription = await stripe.subscriptions.update(user.subscription_id, {
            cancel_at_period_end: true
        });

        // Update user record
        await db.query(
            `UPDATE users SET subscription_status = 'cancelling' WHERE id = ?`,
            [userId]
        );

        res.json({
            success: true,
            message: 'Subscription will be cancelled at the end of the billing period',
            cancel_at: new Date(subscription.cancel_at * 1000)
        });

    } catch (error) {
        console.error('Error cancelling subscription:', error);
        res.status(500).json({ message: 'Failed to cancel subscription: ' + error.message });
    }
};

// Immediately cancel subscription (no refund, immediate access removal)
exports.cancelSubscriptionImmediately = async (req, res) => {
    try {
        const userId = req.user.id;

        // Get user's subscription ID
        const userResult = await db.query('SELECT subscription_id FROM users WHERE id = ?', [userId]);
        const user = userResult.rows[0];

        if (!user?.subscription_id) {
            return res.status(400).json({ message: 'No active subscription found' });
        }

        const stripe = await getStripeInstance();

        // Cancel immediately
        await stripe.subscriptions.cancel(user.subscription_id);

        // Determine new role (downgrade to normal if pro)
        let newRole = user.role;
        if (newRole === 'pro') {
            newRole = 'normal';
        }

        // Update user record
        await db.query(
            `UPDATE users SET 
                subscription_plan = 'free', 
                subscription_id = NULL,
                subscription_status = 'cancelled',
                renewal_date = NULL,
                role = ?
            WHERE id = ?`,
            [newRole, userId]
        );

        res.json({
            success: true,
            message: 'Subscription cancelled immediately'
        });

    } catch (error) {
        console.error('Error cancelling subscription:', error);
        res.status(500).json({ message: 'Failed to cancel subscription: ' + error.message });
    }
};
