/**
 * Stripe Integration Routes
 * Handles checkout sessions, webhooks, and customer portal
 * Date: April 3, 2026
 * Updated: April 6, 2026 - Added Discord role sync (Task #87)
 * Updated: April 10, 2026 - Added /auth and /checkout routes for Discord OAuth flow
 */

const express = require('express');
const router = express.Router();
const cors = require('cors');
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
const db = require('../database');
const { syncRole, removeAllRoles, downgradeToAwakened } = require('../services/discordRoleSync');
const { welcomeNewMember } = require('../services/awakenedConcierge');
const { syncLuckPermsMeta } = require('../services/luckpermsSync');
const { logAction } = require('../services/discordActionLog');
const { syncWikiUser, demoteToAwakened: demoteWikiToAwakened } = require('../services/wikijsSync');

// CORS configuration for checkout endpoint
const corsOptions = {
  origin: [
    'https://firefrostgaming.com',
    'https://www.firefrostgaming.com',
    'https://firefrost-website.pages.dev' // Cloudflare Pages preview domain
  ],
  methods: ['POST', 'OPTIONS'],
  optionsSuccessStatus: 200
};

// 👇 THE MAGIC LINE - Handle CORS preflight OPTIONS request
router.options('/create-checkout-session', cors(corsOptions));

/**
 * STRIPE AUTH - Entry point from website
 * GET /stripe/auth?tier=X
 * If already logged in, goes straight to checkout
 * If not, stores tier in session and redirects to Discord OAuth
 */
router.get('/auth', (req, res) => {
  const tierLevel = req.query.tier;
  
  if (!tierLevel || isNaN(parseInt(tierLevel))) {
    return res.status(400).send('Invalid tier level. Please return to the subscribe page and try again.');
  }
  
  // If user is already authenticated, skip OAuth and go straight to checkout
  if (req.user && req.user.id) {
    return res.redirect(`/stripe/checkout?tier=${tierLevel}`);
  }
  
  // Store tier in session for after OAuth callback
  req.session.pendingCheckoutTier = parseInt(tierLevel);
  
  // Redirect to Discord OAuth
  res.redirect('/auth/discord');
});

/**
 * CHECKOUT - Creates Stripe session after Discord OAuth
 * GET /stripe/checkout?tier=X
 * Called from auth callback, user is now logged in
 */
router.get('/checkout', async (req, res) => {
  try {
    // User must be authenticated
    if (!req.user || !req.user.id) {
      return res.redirect('/stripe/auth?tier=' + (req.query.tier || '1'));
    }
    
    const tierLevel = parseInt(req.query.tier);
    const discordId = req.user.id;
    
    if (!tierLevel || isNaN(tierLevel)) {
      return res.status(400).send('Invalid tier level');
    }
    
    // Get Stripe Price ID from database
    const productResult = await db.query(
      'SELECT stripe_price_id, tier_name, billing_type FROM stripe_products WHERE tier_level = $1',
      [tierLevel]
    );
    
    if (productResult.rows.length === 0) {
      return res.status(404).send('Invalid tier level - product not found');
    }
    
    const product = productResult.rows[0];
    const priceId = product.stripe_price_id;
    const billingMode = product.billing_type === 'one-time' ? 'payment' : 'subscription';
    
    console.log('🔍 Creating checkout session (OAuth flow):', {
      discord_id: discordId,
      tier_level: tierLevel,
      tier_name: product.tier_name,
      priceId,
      billingMode
    });
    
    // Create Stripe Checkout Session WITH client_reference_id
    const sessionConfig = {
      payment_method_types: ['card'],
      line_items: [{ price: priceId, quantity: 1 }],
      mode: billingMode,
      client_reference_id: discordId, // 🔑 THE KEY - Discord ID for webhook
      success_url: 'https://firefrostgaming.com/success',
      cancel_url: 'https://firefrostgaming.com/subscribe',
      metadata: {
        tier_level: tierLevel.toString(),
        tier_name: product.tier_name,
        discord_id: discordId
      }
    };
    
    const session = await stripe.checkout.sessions.create(sessionConfig);
    
    // Redirect directly to Stripe Checkout
    res.redirect(session.url);
    
  } catch (error) {
    console.error('Checkout creation error:', error);
    res.status(500).send('Failed to create checkout session. Please try again.');
  }
});

/**
 * CREATE CHECKOUT SESSION (Legacy API - kept for compatibility)
 * POST /stripe/create-checkout-session
 * Body: { tier_level }
 * NOTE: This doesn't have Discord ID - use /stripe/auth flow instead
 */
router.post('/create-checkout-session', cors(corsOptions), async (req, res) => {
  try {
    const { tier_level } = req.body;
    
    if (!tier_level) {
      return res.status(400).json({ error: 'Missing tier_level' });
    }
    
    // Get Stripe Price ID from database based on tier level
    const productResult = await db.query(
      'SELECT stripe_price_id, tier_name, billing_type FROM stripe_products WHERE tier_level = $1',
      [tier_level]
    );
    
    if (productResult.rows.length === 0) {
      return res.status(404).json({ error: 'Invalid tier level' });
    }
    
    const product = productResult.rows[0];
    const priceId = product.stripe_price_id;
    const billingMode = product.billing_type === 'one-time' ? 'payment' : 'subscription';
    
    console.log('🔍 Creating checkout session (legacy, no Discord ID):', {
      tier_level,
      tier_name: product.tier_name,
      priceId,
      billingMode
    });
    
    // Create Stripe Checkout Session
    const sessionConfig = {
      payment_method_types: ['card'],
      line_items: [{ price: priceId, quantity: 1 }],
      mode: billingMode,
      success_url: 'https://firefrostgaming.com/success',
      cancel_url: 'https://firefrostgaming.com/subscribe',
      metadata: {
        tier_level: tier_level.toString(),
        tier_name: product.tier_name
      }
    };
    
    const session = await stripe.checkout.sessions.create(sessionConfig);
    
    res.json({ checkout_url: session.url });
    
  } catch (error) {
    console.error('Checkout session error:', error);
    res.status(500).json({ error: 'Failed to create checkout session' });
  }
});

/**
 * STRIPE WEBHOOK HANDLER
 * POST /stripe/webhook
 * Receives events from Stripe (signature verified)
 */
router.post('/webhook', express.raw({ type: 'application/json' }), async (req, res) => {
  const sig = req.headers['stripe-signature'];
  let event;
  
  try {
    event = stripe.webhooks.constructEvent(
      req.body,
      sig,
      process.env.STRIPE_WEBHOOK_SECRET
    );
  } catch (err) {
    console.error('Webhook signature verification failed:', err.message);
    return res.status(400).send(`Webhook Error: ${err.message}`);
  }
  
  // Check for duplicate events (idempotency)
  const existingEvent = await db.query(
    'SELECT stripe_event_id FROM webhook_events_processed WHERE stripe_event_id = $1',
    [event.id]
  );
  
  if (existingEvent.rows.length > 0) {
    console.log(`Duplicate event ${event.id}, skipping`);
    return res.json({ received: true, duplicate: true });
  }
  
  // Process event with transaction safety
  const client = await db.pool.connect();
  
  try {
    await client.query('BEGIN');
    
    switch (event.type) {
      case 'checkout.session.completed': {
        const session = event.data.object;
        const discordId = session.client_reference_id;
        const customerId = session.customer;
        let tierLevel = null;
        
        if (session.mode === 'subscription') {
          // RECURRING SUBSCRIPTION (Tiers 2-9)
          const subId = session.subscription;
          const subscription = await stripe.subscriptions.retrieve(subId);
          const priceId = subscription.items.data[0].price.id;
          
          const productRes = await client.query(
            'SELECT tier_level, price_monthly FROM stripe_products WHERE stripe_price_id = $1',
            [priceId]
          );
          
          if (productRes.rows.length === 0) {
            throw new Error(`Unknown price ID: ${priceId}`);
          }
          
          const tierData = productRes.rows[0];
          tierLevel = tierData.tier_level;
          
          await client.query(`
            INSERT INTO subscriptions (discord_id, tier_level, status, stripe_subscription_id, stripe_customer_id, mrr_value, is_lifetime)
            VALUES ($1, $2, 'active', $3, $4, $5, FALSE)
            ON CONFLICT (stripe_subscription_id) DO UPDATE SET status = 'active', updated_at = CURRENT_TIMESTAMP
          `, [discordId, tierData.tier_level, subId, customerId, tierData.price_monthly]);
          
        } else if (session.mode === 'payment') {
          // ONE-TIME PAYMENT (Awakened or Sovereign)
          const paymentIntentId = session.payment_intent;
          const lineItems = await stripe.checkout.sessions.listLineItems(session.id);
          const priceId = lineItems.data[0].price.id;
          
          const productRes = await client.query(
            'SELECT tier_level, price_monthly FROM stripe_products WHERE stripe_price_id = $1',
            [priceId]
          );
          
          if (productRes.rows.length === 0) {
            throw new Error(`Unknown price ID: ${priceId}`);
          }
          
          const tierData = productRes.rows[0];
          tierLevel = tierData.tier_level;
          
          await client.query(`
            INSERT INTO subscriptions (discord_id, tier_level, status, stripe_payment_intent_id, stripe_customer_id, mrr_value, is_lifetime)
            VALUES ($1, $2, 'lifetime', $3, $4, 0, TRUE)
            ON CONFLICT (stripe_payment_intent_id) DO UPDATE SET status = 'lifetime', updated_at = CURRENT_TIMESTAMP
          `, [discordId, tierData.tier_level, paymentIntentId, customerId]);
        }
        
        // Log successful checkout
        await client.query(`
          INSERT INTO admin_audit_log (action_type, target_identifier, details)
          VALUES ('CHECKOUT_COMPLETED', $1, $2)
        `, [discordId, JSON.stringify({ mode: session.mode, customer: customerId })]);
        
        // Sync Discord role
        if (discordId && tierLevel) {
          const roleResult = await syncRole(discordId, tierLevel);
          console.log(`🎭 Role sync for ${discordId}: ${roleResult.message}`);

          // Welcome new member via Awakened Concierge (non-blocking)
          welcomeNewMember(discordId, client).catch(err =>
            console.error('[Concierge] Background welcome error:', err.message)
          );

          // Sync LuckPerms meta across all online servers (non-blocking)
          syncLuckPermsMeta(discordId, tierLevel).then(result => {
            if (result.success) {
              console.log(`⚔️  LP meta sync for ${result.username}: tier ${tierLevel}, ${result.serversUpdated} servers`);
            } else {
              console.log(`⚠️  LP meta sync skipped for ${discordId}: ${result.reason}`);
            }
          }).catch(err => console.error('[LPSync] Background sync error:', err.message));

          // Sync Wiki.js subscriber group (non-blocking, silent-fail)
          // REQ-2026-04-15-subscriber-wiki-auth (Task #138)
          syncWikiUser(discordId, req.user?.username || discordId, tierLevel)
            .then(r => { if (r.success) console.log(`📚 WikiSync checkout: ${discordId} → ${r.group}`); })
            .catch(err => console.error('[WikiSync] checkout error:', err.message));

          // Carl-bot migration: link-reminder DM for Awakened+ subscribers (non-blocking, silent-fail)
          // REQ-2026-04-15-reaction-roles (Chronicler #92)
          (async () => {
            try {
              const discordClient = req.app.locals.client;
              if (!discordClient) return;
              const user = await discordClient.users.fetch(discordId).catch(() => null);
              if (!user) return;
              await user.send(
                `Hey ${user.username}! You're now part of the Firefrost family! 🎉\n\n` +
                `One quick step — head to #link-your-account and use the /link command ` +
                `to connect your Minecraft account so we can whitelist you on our servers.\n\n` +
                `See you in-game!`
              );
              console.log(`💌 [LinkReminder] sent to ${user.username}`);
              logAction('link_reminder_dm', discordId, user.username, { tierLevel }, true, null);
            } catch (err) {
              console.log(`[LinkReminder] DM to ${discordId} skipped: ${err.message}`);
              logAction('link_reminder_dm', discordId, null, { tierLevel }, false, err.message);
            }
          })();
        }
        
        break;
      }
      
      case 'customer.subscription.updated': {
        const subscription = event.data.object;
        const subId = subscription.id;
        const status = subscription.status; // active, past_due, canceled, etc.
        
        await client.query(`
          UPDATE subscriptions 
          SET status = $1, updated_at = CURRENT_TIMESTAMP 
          WHERE stripe_subscription_id = $2
        `, [status, subId]);
        
        break;
      }
      
      case 'customer.subscription.deleted': {
        // Task #126: "We don't kick people out."
        // Awakened ($1) is lifetime. When a paid subscription ends (cancellation
        // or Stripe gave up on retries), demote to Awakened rather than remove.
        // This event fires at actual period end, so timing is already correct.
        const subscription = event.data.object;
        const subId = subscription.id;
        
        // Find the Discord ID for this subscription before updating status
        const subRow = await client.query(
          'SELECT discord_id FROM subscriptions WHERE stripe_subscription_id = $1',
          [subId]
        );
        
        await client.query(`
          UPDATE subscriptions 
          SET status = 'lifetime', 
              tier_level = 1,
              is_lifetime = TRUE,
              grace_period_started_at = NULL,
              grace_period_ends_at = NULL,
              updated_at = CURRENT_TIMESTAMP
          WHERE stripe_subscription_id = $1 AND is_lifetime = FALSE
        `, [subId]);
        
        // Demote Discord role to Awakened (strips tier role, assigns Awakened)
        if (subRow.rows.length > 0) {
          const discordId = subRow.rows[0].discord_id;
          const roleResult = await downgradeToAwakened(discordId);
          console.log(`⬇️  Subscription ended for ${discordId}, demoted to Awakened: ${roleResult.message}`);

          // Demote Wiki.js group to Awakened (non-blocking, silent-fail)
          demoteWikiToAwakened(discordId)
            .catch(err => console.error('[WikiSync] demote error:', err.message));
          
          await client.query(`
            INSERT INTO admin_audit_log (action_type, target_identifier, details)
            VALUES ('SUBSCRIPTION_ENDED_DEMOTED', $1, $2)
          `, [discordId, JSON.stringify({ 
            stripe_subscription_id: subId,
            reason: 'subscription_deleted',
            policy: 'we_dont_kick_people_out'
          })]);
        }
        
        break;
      }
      
      case 'invoice.payment_failed': {
        const invoice = event.data.object;
        const subId = invoice.subscription;
        
        if (subId) {
          await client.query(`
            UPDATE subscriptions 
            SET status = 'past_due',
                payment_failure_reason = $1,
                last_payment_attempt = CURRENT_TIMESTAMP,
                updated_at = CURRENT_TIMESTAMP
            WHERE stripe_subscription_id = $2
          `, [invoice.failure_message || 'Payment failed', subId]);
        }
        
        break;
      }
      
      case 'invoice.payment_succeeded': {
        const invoice = event.data.object;
        const subId = invoice.subscription;
        
        if (subId) {
          // Clear grace period if payment succeeded
          await client.query(`
            UPDATE subscriptions 
            SET status = 'active',
                grace_period_started_at = NULL,
                grace_period_ends_at = NULL,
                payment_failure_reason = NULL,
                updated_at = CURRENT_TIMESTAMP
            WHERE stripe_subscription_id = $1
          `, [subId]);
        }
        
        break;
      }
      
      case 'charge.dispute.created': {
        const dispute = event.data.object;
        const paymentIntentId = dispute.payment_intent;
        const customerId = dispute.customer;
        
        // Find the subscription by customer ID (more reliable)
        const subResult = await client.query(`
          SELECT discord_id FROM subscriptions 
          WHERE stripe_customer_id = $1
          LIMIT 1
        `, [customerId]);
        
        let discordId = null;
        if (subResult.rows.length > 0) {
          discordId = subResult.rows[0].discord_id;
        }
        
        // Mark as banned
        await client.query(`
          UPDATE subscriptions 
          SET status = 'chargeback_ban',
              updated_at = CURRENT_TIMESTAMP
          WHERE stripe_customer_id = $1
        `, [customerId]);
        
        // Add to banned_users table
        if (discordId) {
          await client.query(`
            INSERT INTO banned_users (discord_id, ban_reason, notes)
            VALUES ($1, 'chargeback', $2)
            ON CONFLICT (discord_id) DO UPDATE SET 
              ban_reason = 'chargeback',
              notes = $2,
              banned_at = CURRENT_TIMESTAMP
          `, [discordId, JSON.stringify({ 
            payment_intent: paymentIntentId,
            dispute_id: dispute.id 
          })]);
          
          // Remove all Discord roles
          const roleResult = await removeAllRoles(discordId);
          console.log(`🚫 Chargeback role removal for ${discordId}: ${roleResult.message}`);
          demoteWikiToAwakened(discordId)
            .catch(err => console.error('[WikiSync] chargeback demote error:', err.message));
        }
        
        await client.query(`
          INSERT INTO admin_audit_log (action_type, target_identifier, details)
          VALUES ('CHARGEBACK_BAN', $1, $2)
        `, [discordId || 'unknown', JSON.stringify({ 
          payment_intent: paymentIntentId, 
          customer_id: customerId,
          reason: 'Chargeback dispute created' 
        })]);
        
        break;
      }
      
      case 'charge.refunded': {
        // Task #126: Refund requested = hard ban, with Trinity appeal process.
        // Policy: "We only remove all access for actionable hard bans."
        // A refund is the customer asking for their money back — mirrors chargeback.
        const charge = event.data.object;
        const customerId = charge.customer;
        const paymentIntentId = charge.payment_intent;
        
        if (!customerId) {
          console.log(`⚠️  charge.refunded with no customer_id (likely guest checkout), skipping`);
          break;
        }
        
        // Find the subscription by customer ID
        const subResult = await client.query(
          'SELECT discord_id FROM subscriptions WHERE stripe_customer_id = $1 LIMIT 1',
          [customerId]
        );
        
        let discordId = null;
        if (subResult.rows.length > 0) {
          discordId = subResult.rows[0].discord_id;
        }
        
        // Mark subscription as refund_ban
        await client.query(`
          UPDATE subscriptions 
          SET status = 'refund_ban',
              updated_at = CURRENT_TIMESTAMP
          WHERE stripe_customer_id = $1
        `, [customerId]);
        
        // Add to banned_users with appeal eligibility noted
        if (discordId) {
          await client.query(`
            INSERT INTO banned_users (discord_id, ban_reason, notes)
            VALUES ($1, 'refund', $2)
            ON CONFLICT (discord_id) DO UPDATE SET 
              ban_reason = 'refund',
              notes = $2,
              banned_at = CURRENT_TIMESTAMP
          `, [discordId, JSON.stringify({ 
            payment_intent: paymentIntentId,
            charge_id: charge.id,
            amount_refunded: charge.amount_refunded,
            appeal_eligible: true,
            appeal_process: 'Trinity review'
          })]);
          
          // Remove ALL roles including Awakened (hard ban)
          const roleResult = await removeAllRoles(discordId);
          console.log(`🚫 Refund ban for ${discordId}: ${roleResult.message}`);
          demoteWikiToAwakened(discordId)
            .catch(err => console.error('[WikiSync] refund ban demote error:', err.message));
        }
        
        await client.query(`
          INSERT INTO admin_audit_log (action_type, target_identifier, details)
          VALUES ('REFUND_BAN', $1, $2)
        `, [discordId || 'unknown', JSON.stringify({ 
          payment_intent: paymentIntentId, 
          customer_id: customerId,
          amount_refunded: charge.amount_refunded,
          reason: 'Refund processed',
          appeal_eligible: true
        })]);
        
        break;
      }
      
      default:
        console.log(`Unhandled event type: ${event.type}`);
    }
    
    // Mark event as processed
    await client.query(
      'INSERT INTO webhook_events_processed (stripe_event_id, event_type) VALUES ($1, $2)',
      [event.id, event.type]
    );
    
    await client.query('COMMIT');
    
  } catch (error) {
    await client.query('ROLLBACK');
    console.error('Webhook processing error:', error);
    return res.status(500).json({ error: 'Webhook processing failed' });
  } finally {
    client.release();
  }
  
  res.json({ received: true });
});

/**
 * CREATE CUSTOMER PORTAL SESSION
 * POST /stripe/create-portal-session
 * Body: { customerId }
 */
router.post('/create-portal-session', async (req, res) => {
  try {
    const { customerId } = req.body;
    
    if (!customerId) {
      return res.status(400).json({ error: 'Missing customerId' });
    }
    
    const portalSession = await stripe.billingPortal.sessions.create({
      customer: customerId,
      return_url: `${process.env.BASE_URL || 'https://discord-bot.firefrostgaming.com'}/admin`
    });
    
    res.json({ url: portalSession.url });
    
  } catch (error) {
    console.error('Portal session error:', error);
    res.status(500).json({ error: 'Failed to create portal session' });
  }
});

module.exports = router;
