const express = require('express');
const session = require('express-session');
const cookieParser = require('cookie-parser');
const cors = require('cors');
const path = require('path');
const crypto = require('crypto');
const Stripe = require('stripe');

function createWebServer(discordClient, supabase, options = {}) {
  const app = express();
  
  const stripe = process.env.STRIPE_SECRET_KEY ? new Stripe(process.env.STRIPE_SECRET_KEY) : null;
  const STRIPE_WEBHOOK_SECRET = process.env.STRIPE_WEBHOOK_SECRET;
  
  const DISCORD_CLIENT_ID = process.env.DISCORD_CLIENT_ID;
  const DISCORD_CLIENT_SECRET = process.env.DISCORD_CLIENT_SECRET;
  const SESSION_SECRET = process.env.SESSION_SECRET || crypto.randomBytes(32).toString('hex');
  // Production URL for OAuth
  const BASE_URL = process.env.BASE_URL || 'https://bot.aethex.dev';
  
  app.use(cors({
    origin: true,
    credentials: true
  }));
  app.use(cookieParser());
  
  // Stripe webhook must be registered BEFORE express.json() to access raw body
  app.post('/api/stripe/webhook', express.raw({ type: 'application/json' }), async (req, res) => {
    if (!stripe || !STRIPE_WEBHOOK_SECRET) {
      return res.status(503).json({ error: 'Stripe webhook not configured' });
    }
    
    const sig = req.headers['stripe-signature'];
    let event;
    
    try {
      event = stripe.webhooks.constructEvent(req.body, sig, STRIPE_WEBHOOK_SECRET);
    } catch (err) {
      console.error('Webhook signature verification failed:', err.message);
      return res.status(400).send(`Webhook Error: ${err.message}`);
    }
    
    try {
      switch (event.type) {
        case 'checkout.session.completed': {
          const session = event.data.object;
          const { guild_id, plan_type } = session.metadata;
          
          if (plan_type === 'premium') {
            await supabase.from('federation_servers').update({
              tier: 'premium',
              subscription_id: session.subscription,
              subscription_status: 'active',
              updated_at: new Date().toISOString()
            }).eq('guild_id', guild_id);
            
            console.log(`[Stripe] Guild ${guild_id} upgraded to premium`);
          } else if (plan_type === 'featured') {
            const expiresAt = new Date();
            expiresAt.setDate(expiresAt.getDate() + 7);
            
            await supabase.from('federation_featured').upsert({
              guild_id: guild_id,
              subscription_id: session.subscription,
              active: true,
              expires_at: expiresAt.toISOString(),
              created_at: new Date().toISOString()
            }, { onConflict: 'guild_id' });
            
            console.log(`[Stripe] Guild ${guild_id} purchased featured slot`);
          }
          break;
        }
        
        case 'customer.subscription.updated': {
          const subscription = event.data.object;
          const status = subscription.status;
          
          if (status === 'active') {
            await supabase.from('federation_servers').update({
              subscription_status: 'active'
            }).eq('subscription_id', subscription.id);
          } else if (status === 'past_due' || status === 'unpaid') {
            await supabase.from('federation_servers').update({
              subscription_status: status
            }).eq('subscription_id', subscription.id);
          }
          break;
        }
        
        case 'customer.subscription.deleted': {
          const subscription = event.data.object;
          
          await supabase.from('federation_servers').update({
            tier: 'free',
            subscription_id: null,
            subscription_status: null,
            updated_at: new Date().toISOString()
          }).eq('subscription_id', subscription.id);
          
          await supabase.from('federation_featured').update({
            active: false
          }).eq('subscription_id', subscription.id);
          
          console.log(`[Stripe] Subscription ${subscription.id} canceled`);
          break;
        }
      }
      
      res.json({ received: true });
    } catch (error) {
      console.error('Webhook processing error:', error);
      res.status(500).json({ error: 'Webhook processing failed' });
    }
  });
  
  app.use(express.json());
  app.use(express.urlencoded({ extended: true }));
  
  app.use(session({
    secret: SESSION_SECRET,
    resave: false,
    saveUninitialized: false,
    cookie: {
      secure: process.env.NODE_ENV === 'production',
      httpOnly: true,
      maxAge: 7 * 24 * 60 * 60 * 1000
    }
  }));
  
  app.use((req, res, next) => {
    res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate');
    res.setHeader('Pragma', 'no-cache');
    res.setHeader('Expires', '0');
    next();
  });
  
  app.use(express.static(path.join(__dirname, '../public')));
  
  app.get('/auth/discord', (req, res) => {
    if (!DISCORD_CLIENT_SECRET) {
      return res.status(500).json({ error: 'Discord OAuth not configured. Please set DISCORD_CLIENT_SECRET.' });
    }
    
    const state = crypto.randomBytes(16).toString('hex');
    req.session.oauthState = state;
    
    const redirectUri = `${BASE_URL}/auth/callback`;
    const scope = 'identify guilds';
    
    const authUrl = `https://discord.com/api/oauth2/authorize?` +
      `client_id=${DISCORD_CLIENT_ID}` +
      `&redirect_uri=${encodeURIComponent(redirectUri)}` +
      `&response_type=code` +
      `&scope=${encodeURIComponent(scope)}` +
      `&state=${state}`;
    
    res.redirect(authUrl);
  });
  
  app.get('/auth/callback', async (req, res) => {
    const { code, state } = req.query;
    
    if (!code) {
      return res.redirect('/?error=no_code');
    }
    
    if (state !== req.session.oauthState) {
      return res.redirect('/?error=invalid_state');
    }
    
    try {
      const redirectUri = `${BASE_URL}/auth/callback`;
      
      const tokenResponse = await fetch('https://discord.com/api/oauth2/token', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/x-www-form-urlencoded'
        },
        body: new URLSearchParams({
          client_id: DISCORD_CLIENT_ID,
          client_secret: DISCORD_CLIENT_SECRET,
          grant_type: 'authorization_code',
          code,
          redirect_uri: redirectUri
        })
      });
      
      if (!tokenResponse.ok) {
        console.error('Token exchange failed:', await tokenResponse.text());
        return res.redirect('/?error=token_failed');
      }
      
      const tokens = await tokenResponse.json();
      
      const userResponse = await fetch('https://discord.com/api/users/@me', {
        headers: {
          Authorization: `Bearer ${tokens.access_token}`
        }
      });
      
      if (!userResponse.ok) {
        return res.redirect('/?error=user_fetch_failed');
      }
      
      const user = await userResponse.json();
      
      const guildsResponse = await fetch('https://discord.com/api/users/@me/guilds', {
        headers: {
          Authorization: `Bearer ${tokens.access_token}`
        }
      });
      
      let guilds = [];
      if (guildsResponse.ok) {
        guilds = await guildsResponse.json();
      }
      
      req.session.user = {
        id: user.id,
        username: user.username,
        discriminator: user.discriminator,
        avatar: user.avatar,
        globalName: user.global_name,
        accessToken: tokens.access_token,
        refreshToken: tokens.refresh_token,
        guilds: guilds.map(g => ({
          id: g.id,
          name: g.name,
          icon: g.icon,
          owner: g.owner,
          permissions: g.permissions,
          isAdmin: (parseInt(g.permissions) & 0x20) === 0x20
        }))
      };
      
      res.redirect('/dashboard');
      
    } catch (error) {
      console.error('OAuth callback error:', error);
      res.redirect('/?error=auth_failed');
    }
  });
  
  app.get('/auth/logout', (req, res) => {
    req.session.destroy();
    res.redirect('/');
  });
  
  app.get('/api/me', (req, res) => {
    if (!req.session.user) {
      return res.status(401).json({ error: 'Not authenticated' });
    }
    
    const user = req.session.user;
    res.json({
      id: user.id,
      username: user.username,
      discriminator: user.discriminator,
      avatar: user.avatar,
      globalName: user.globalName,
      avatarUrl: user.avatar 
        ? `https://cdn.discordapp.com/avatars/${user.id}/${user.avatar}.png`
        : `https://cdn.discordapp.com/embed/avatars/${parseInt(user.discriminator || '0') % 5}.png`,
      guilds: user.guilds.map(g => ({
        ...g,
        icon: g.icon ? `https://cdn.discordapp.com/icons/${g.id}/${g.icon}.png` : null
      }))
    });
  });
  
  // Profile handler function
  async function handleProfileRequest(req, res, userId) {
    if (!supabase) {
      return res.status(503).json({ error: 'Database not available' });
    }
    
    const targetUserId = userId || req.session.user?.id;
    if (!targetUserId) {
      return res.status(400).json({ error: 'User ID required' });
    }
    
    try {
      const { data: link } = await supabase
        .from('discord_links')
        .select('user_id')
        .eq('discord_id', targetUserId)
        .maybeSingle();
      
      if (!link) {
        return res.json({ linked: false, message: 'Discord account not linked' });
      }
      
      const { data: profile } = await supabase
        .from('user_profiles')
        .select('*')
        .eq('id', link.user_id)
        .maybeSingle();
      
      if (!profile) {
        return res.json({ linked: true, profile: null });
      }
      
      res.json({
        linked: true,
        profile: {
          id: profile.id,
          username: profile.username,
          xp: profile.xp || 0,
          prestigeLevel: profile.prestige_level || 0,
          totalXpEarned: profile.total_xp_earned || 0,
          dailyStreak: profile.daily_streak || 0,
          title: profile.title,
          bio: profile.bio,
          avatarUrl: profile.avatar_url,
          createdAt: profile.created_at
        }
      });
    } catch (error) {
      console.error('Profile fetch error:', error);
      res.status(500).json({ error: 'Failed to fetch profile' });
    }
  }
  
  // Route for current user's profile
  app.get('/api/profile', (req, res) => handleProfileRequest(req, res, null));
  
  // Route for specific user's profile
  app.get('/api/profile/:userId', (req, res) => handleProfileRequest(req, res, req.params.userId));
  
  app.get('/api/stats/:userId/:guildId', async (req, res) => {
    if (!supabase) {
      return res.status(503).json({ error: 'Database not available' });
    }
    
    const { userId, guildId } = req.params;
    
    try {
      const { data: link } = await supabase
        .from('discord_links')
        .select('user_id')
        .eq('discord_id', userId)
        .maybeSingle();
      
      if (!link) {
        return res.json({ stats: null });
      }
      
      const { data: stats } = await supabase
        .from('user_stats')
        .select('*')
        .eq('user_id', link.user_id)
        .eq('guild_id', guildId)
        .maybeSingle();
      
      res.json({ stats });
    } catch (error) {
      res.status(500).json({ error: 'Failed to fetch stats' });
    }
  });
  
  app.get('/api/achievements/:guildId', async (req, res) => {
    if (!supabase) {
      return res.status(503).json({ error: 'Database not available' });
    }
    
    const { guildId } = req.params;
    const userId = req.session.user?.id;
    
    try {
      const { data: achievements } = await supabase
        .from('achievements')
        .select('*')
        .eq('guild_id', guildId)
        .eq('hidden', false)
        .order('created_at', { ascending: true });
      
      let userAchievements = [];
      if (userId) {
        const { data: link } = await supabase
          .from('discord_links')
          .select('user_id')
          .eq('discord_id', userId)
          .maybeSingle();
        
        if (link) {
          const { data } = await supabase
            .from('user_achievements')
            .select('achievement_id, earned_at')
            .eq('user_id', link.user_id)
            .eq('guild_id', guildId);
          userAchievements = data || [];
        }
      }
      
      res.json({ achievements, userAchievements });
    } catch (error) {
      res.status(500).json({ error: 'Failed to fetch achievements' });
    }
  });
  
  app.get('/api/quests/:guildId', async (req, res) => {
    if (!supabase) {
      return res.status(503).json({ error: 'Database not available' });
    }
    
    const { guildId } = req.params;
    const userId = req.session.user?.id;
    
    try {
      const now = new Date().toISOString();
      const { data: quests } = await supabase
        .from('quests')
        .select('*')
        .eq('guild_id', guildId)
        .eq('active', true)
        .or(`starts_at.is.null,starts_at.lte.${now}`)
        .or(`expires_at.is.null,expires_at.gt.${now}`)
        .order('created_at', { ascending: false });
      
      let userQuests = [];
      if (userId) {
        const { data: link } = await supabase
          .from('discord_links')
          .select('user_id')
          .eq('discord_id', userId)
          .maybeSingle();
        
        if (link) {
          const { data } = await supabase
            .from('user_quests')
            .select('*')
            .eq('user_id', link.user_id)
            .eq('guild_id', guildId);
          userQuests = data || [];
        }
      }
      
      res.json({ quests, userQuests });
    } catch (error) {
      res.status(500).json({ error: 'Failed to fetch quests' });
    }
  });
  
  app.get('/api/shop/:guildId', async (req, res) => {
    if (!supabase) {
      return res.status(503).json({ error: 'Database not available' });
    }
    
    const { guildId } = req.params;
    
    try {
      const { data: items } = await supabase
        .from('shop_items')
        .select('*')
        .eq('guild_id', guildId)
        .eq('enabled', true)
        .order('price', { ascending: true });
      
      res.json({ items: items || [] });
    } catch (error) {
      res.status(500).json({ error: 'Failed to fetch shop items' });
    }
  });
  
  app.get('/api/inventory/:guildId', async (req, res) => {
    if (!supabase) {
      return res.status(503).json({ error: 'Database not available' });
    }
    
    const userId = req.session.user?.id;
    if (!userId) {
      return res.status(401).json({ error: 'Not authenticated' });
    }
    
    const { guildId } = req.params;
    
    try {
      const { data: link } = await supabase
        .from('discord_links')
        .select('user_id')
        .eq('discord_id', userId)
        .maybeSingle();
      
      if (!link) {
        return res.json({ inventory: [] });
      }
      
      const { data: inventory } = await supabase
        .from('user_inventory')
        .select(`
          *,
          shop_items (name, description, item_type, item_data)
        `)
        .eq('user_id', link.user_id)
        .eq('guild_id', guildId);
      
      res.json({ inventory: inventory || [] });
    } catch (error) {
      res.status(500).json({ error: 'Failed to fetch inventory' });
    }
  });
  
  app.get('/api/leaderboard/:guildId', async (req, res) => {
    if (!supabase) {
      return res.status(503).json({ error: 'Database not available' });
    }
    
    const { guildId } = req.params;
    const { type = 'all', limit = 50 } = req.query;
    
    try {
      let tableName = 'leaderboard_alltime';
      if (type === 'weekly') tableName = 'leaderboard_weekly';
      else if (type === 'monthly') tableName = 'leaderboard_monthly';
      
      const { data: leaderboard } = await supabase
        .from(tableName)
        .select(`
          *,
          user_profiles!inner (username, avatar_url, prestige_level)
        `)
        .eq('guild_id', guildId)
        .order('xp', { ascending: false })
        .limit(parseInt(limit));
      
      res.json({ leaderboard: leaderboard || [], type });
    } catch (error) {
      res.status(500).json({ error: 'Failed to fetch leaderboard' });
    }
  });
  
  app.get('/api/bot-stats', (req, res) => {
    const stats = {
      guilds: discordClient.guilds.cache.size,
      users: discordClient.guilds.cache.reduce((acc, g) => acc + g.memberCount, 0),
      commands: discordClient.commands?.size || 0,
      uptime: Math.floor(process.uptime()),
      status: discordClient.user ? 'online' : 'offline',
      botName: discordClient.user?.username || 'AeThex',
      botAvatar: discordClient.user?.displayAvatarURL() || null
    };
    res.json(stats);
  });
  
  app.get('/api/guild/:guildId/config', async (req, res) => {
    if (!supabase) {
      return res.status(503).json({ error: 'Database not available' });
    }
    
    const userId = req.session.user?.id;
    if (!userId) {
      return res.status(401).json({ error: 'Not authenticated' });
    }
    
    const { guildId } = req.params;
    
    const userGuild = req.session.user.guilds.find(g => g.id === guildId);
    if (!userGuild || !userGuild.isAdmin) {
      return res.status(403).json({ error: 'No admin access to this server' });
    }
    
    try {
      const { data: xpConfig } = await supabase
        .from('xp_config')
        .select('*')
        .eq('guild_id', guildId)
        .maybeSingle();
      
      const { data: serverConfig } = await supabase
        .from('server_config')
        .select('*')
        .eq('guild_id', guildId)
        .maybeSingle();
      
      res.json({ xpConfig, serverConfig });
    } catch (error) {
      res.status(500).json({ error: 'Failed to fetch config' });
    }
  });
  
  app.post('/api/guild/:guildId/xp-config', async (req, res) => {
    if (!supabase) {
      return res.status(503).json({ error: 'Database not available' });
    }
    
    const userId = req.session.user?.id;
    if (!userId) {
      return res.status(401).json({ error: 'Not authenticated' });
    }
    
    const { guildId } = req.params;
    
    const userGuild = req.session.user.guilds.find(g => g.id === guildId);
    if (!userGuild || !userGuild.isAdmin) {
      return res.status(403).json({ error: 'No admin access to this server' });
    }
    
    const {
      message_xp,
      message_cooldown,
      reaction_xp_enabled,
      reaction_xp_given,
      reaction_xp_received,
      reaction_cooldown,
      level_curve,
      xp_enabled,
      levelup_channel_id,
      levelup_message,
      levelup_dm,
      levelup_embed,
      levelup_embed_color,
      multiplier_roles,
      bonus_channels
    } = req.body;
    
    try {
      const { data: existing } = await supabase
        .from('xp_config')
        .select('guild_id')
        .eq('guild_id', guildId)
        .maybeSingle();
      
      const configData = {
        guild_id: guildId,
        message_xp: message_xp ?? 15,
        message_cooldown: message_cooldown ?? 60,
        reaction_xp_enabled: reaction_xp_enabled !== false,
        reaction_xp_given: reaction_xp_given ?? 2,
        reaction_xp_received: reaction_xp_received ?? 5,
        reaction_cooldown: reaction_cooldown ?? 30,
        level_curve: level_curve || 'normal',
        xp_enabled: xp_enabled !== false,
        levelup_channel_id: levelup_channel_id || null,
        levelup_message: levelup_message || null,
        levelup_dm: levelup_dm === true,
        levelup_embed: levelup_embed !== false,
        levelup_embed_color: levelup_embed_color || '#7c3aed',
        multiplier_roles: multiplier_roles || [],
        bonus_channels: bonus_channels || [],
        updated_at: new Date().toISOString()
      };
      
      if (existing) {
        const { error } = await supabase
          .from('xp_config')
          .update(configData)
          .eq('guild_id', guildId);
        
        if (error) throw error;
      } else {
        const { error } = await supabase
          .from('xp_config')
          .insert(configData);
        
        if (error) throw error;
      }
      
      res.json({ success: true });
    } catch (error) {
      console.error('Failed to save XP config:', error);
      res.status(500).json({ error: 'Failed to save settings', details: error.message });
    }
  });
  
  app.get('/api/guild/:guildId/quests', async (req, res) => {
    if (!supabase) {
      return res.status(503).json({ error: 'Database not available' });
    }
    
    const userId = req.session.user?.id;
    if (!userId) {
      return res.status(401).json({ error: 'Not authenticated' });
    }
    
    const { guildId } = req.params;
    
    const userGuild = req.session.user.guilds.find(g => g.id === guildId);
    if (!userGuild || !userGuild.isAdmin) {
      return res.status(403).json({ error: 'No admin access' });
    }
    
    try {
      const { data: quests } = await supabase
        .from('quests')
        .select('*')
        .eq('guild_id', guildId)
        .order('created_at', { ascending: false });
      
      res.json({ quests: quests || [] });
    } catch (error) {
      res.status(500).json({ error: 'Failed to fetch quests' });
    }
  });
  
  app.post('/api/guild/:guildId/quests', async (req, res) => {
    if (!supabase) {
      return res.status(503).json({ error: 'Database not available' });
    }
    
    const userId = req.session.user?.id;
    if (!userId) {
      return res.status(401).json({ error: 'Not authenticated' });
    }
    
    const { guildId } = req.params;
    
    const userGuild = req.session.user.guilds.find(g => g.id === guildId);
    if (!userGuild || !userGuild.isAdmin) {
      return res.status(403).json({ error: 'No admin access' });
    }
    
    const { name, description, quest_type, objective, target_value, xp_reward, duration_hours, repeatable, active } = req.body;
    
    try {
      const questData = {
        guild_id: guildId,
        name,
        description: description || null,
        quest_type: quest_type || 'daily',
        objective: objective || 'messages',
        target_value: target_value || 10,
        xp_reward: xp_reward || 100,
        repeatable: repeatable || false,
        active: active !== false,
        created_at: new Date().toISOString()
      };
      
      if (duration_hours && duration_hours > 0) {
        const expiry = new Date();
        expiry.setHours(expiry.getHours() + duration_hours);
        questData.expires_at = expiry.toISOString();
      }
      
      const { error } = await supabase.from('quests').insert(questData);
      
      if (error) throw error;
      
      res.json({ success: true });
    } catch (error) {
      console.error('Failed to create quest:', error);
      res.status(500).json({ error: 'Failed to create quest' });
    }
  });
  
  app.put('/api/guild/:guildId/quests/:questId', async (req, res) => {
    if (!supabase) {
      return res.status(503).json({ error: 'Database not available' });
    }
    
    const userId = req.session.user?.id;
    if (!userId) {
      return res.status(401).json({ error: 'Not authenticated' });
    }
    
    const { guildId, questId } = req.params;
    
    const userGuild = req.session.user.guilds.find(g => g.id === guildId);
    if (!userGuild || !userGuild.isAdmin) {
      return res.status(403).json({ error: 'No admin access' });
    }
    
    const { name, description, quest_type, objective, target_value, xp_reward, repeatable, active } = req.body;
    
    try {
      const { error } = await supabase
        .from('quests')
        .update({
          name,
          description: description || null,
          quest_type,
          objective,
          target_value,
          xp_reward,
          repeatable: repeatable || false,
          active
        })
        .eq('id', questId)
        .eq('guild_id', guildId);
      
      if (error) throw error;
      
      res.json({ success: true });
    } catch (error) {
      console.error('Failed to update quest:', error);
      res.status(500).json({ error: 'Failed to update quest' });
    }
  });
  
  app.delete('/api/guild/:guildId/quests/:questId', async (req, res) => {
    if (!supabase) {
      return res.status(503).json({ error: 'Database not available' });
    }
    
    const userId = req.session.user?.id;
    if (!userId) {
      return res.status(401).json({ error: 'Not authenticated' });
    }
    
    const { guildId, questId } = req.params;
    
    const userGuild = req.session.user.guilds.find(g => g.id === guildId);
    if (!userGuild || !userGuild.isAdmin) {
      return res.status(403).json({ error: 'No admin access' });
    }
    
    try {
      const { error } = await supabase
        .from('quests')
        .delete()
        .eq('id', questId)
        .eq('guild_id', guildId);
      
      if (error) throw error;
      
      res.json({ success: true });
    } catch (error) {
      console.error('Failed to delete quest:', error);
      res.status(500).json({ error: 'Failed to delete quest' });
    }
  });
  
  // ============ ACHIEVEMENTS ADMIN API ============
  
  app.get('/api/guild/:guildId/achievements', async (req, res) => {
    if (!supabase) {
      return res.status(503).json({ error: 'Database not available' });
    }
    
    const userId = req.session.user?.id;
    if (!userId) {
      return res.status(401).json({ error: 'Not authenticated' });
    }
    
    const { guildId } = req.params;
    
    const userGuild = req.session.user.guilds.find(g => g.id === guildId);
    if (!userGuild || !userGuild.isAdmin) {
      return res.status(403).json({ error: 'No admin access' });
    }
    
    try {
      const { data: achievements } = await supabase
        .from('achievements')
        .select('*')
        .eq('guild_id', guildId)
        .order('created_at', { ascending: false });
      
      res.json({ achievements: achievements || [] });
    } catch (error) {
      console.error('Failed to fetch achievements:', error);
      res.status(500).json({ error: 'Failed to fetch achievements' });
    }
  });
  
  app.post('/api/guild/:guildId/achievements', async (req, res) => {
    if (!supabase) {
      return res.status(503).json({ error: 'Database not available' });
    }
    
    const userId = req.session.user?.id;
    if (!userId) {
      return res.status(401).json({ error: 'Not authenticated' });
    }
    
    const { guildId } = req.params;
    
    const userGuild = req.session.user.guilds.find(g => g.id === guildId);
    if (!userGuild || !userGuild.isAdmin) {
      return res.status(403).json({ error: 'No admin access' });
    }
    
    const { name, icon, description, trigger_type, trigger_value, reward_xp, reward_role_id, hidden } = req.body;
    
    try {
      const achievementData = {
        guild_id: guildId,
        name,
        icon: icon || '🏆',
        description: description || null,
        trigger_type: trigger_type || 'level',
        trigger_value: trigger_value || 1,
        reward_xp: reward_xp || 0,
        reward_role_id: reward_role_id || null,
        hidden: hidden || false,
        created_at: new Date().toISOString()
      };
      
      const { error } = await supabase.from('achievements').insert(achievementData);
      
      if (error) throw error;
      
      res.json({ success: true });
    } catch (error) {
      console.error('Failed to create achievement:', error);
      res.status(500).json({ error: 'Failed to create achievement' });
    }
  });
  
  app.put('/api/guild/:guildId/achievements/:achievementId', async (req, res) => {
    if (!supabase) {
      return res.status(503).json({ error: 'Database not available' });
    }
    
    const userId = req.session.user?.id;
    if (!userId) {
      return res.status(401).json({ error: 'Not authenticated' });
    }
    
    const { guildId, achievementId } = req.params;
    
    const userGuild = req.session.user.guilds.find(g => g.id === guildId);
    if (!userGuild || !userGuild.isAdmin) {
      return res.status(403).json({ error: 'No admin access' });
    }
    
    const { name, icon, description, trigger_type, trigger_value, reward_xp, reward_role_id, hidden } = req.body;
    
    try {
      const { error } = await supabase
        .from('achievements')
        .update({
          name,
          icon: icon || '🏆',
          description: description || null,
          trigger_type,
          trigger_value,
          reward_xp: reward_xp || 0,
          reward_role_id: reward_role_id || null,
          hidden: hidden || false
        })
        .eq('id', achievementId)
        .eq('guild_id', guildId);
      
      if (error) throw error;
      
      res.json({ success: true });
    } catch (error) {
      console.error('Failed to update achievement:', error);
      res.status(500).json({ error: 'Failed to update achievement' });
    }
  });
  
  app.delete('/api/guild/:guildId/achievements/:achievementId', async (req, res) => {
    if (!supabase) {
      return res.status(503).json({ error: 'Database not available' });
    }
    
    const userId = req.session.user?.id;
    if (!userId) {
      return res.status(401).json({ error: 'Not authenticated' });
    }
    
    const { guildId, achievementId } = req.params;
    
    const userGuild = req.session.user.guilds.find(g => g.id === guildId);
    if (!userGuild || !userGuild.isAdmin) {
      return res.status(403).json({ error: 'No admin access' });
    }
    
    try {
      const { error } = await supabase
        .from('achievements')
        .delete()
        .eq('id', achievementId)
        .eq('guild_id', guildId);
      
      if (error) throw error;
      
      res.json({ success: true });
    } catch (error) {
      console.error('Failed to delete achievement:', error);
      res.status(500).json({ error: 'Failed to delete achievement' });
    }
  });
  
  // ============ SHOP ADMIN API ============
  
  app.get('/api/guild/:guildId/shop/admin', async (req, res) => {
    if (!supabase) {
      return res.status(503).json({ error: 'Database not available' });
    }
    
    const userId = req.session.user?.id;
    if (!userId) {
      return res.status(401).json({ error: 'Not authenticated' });
    }
    
    const { guildId } = req.params;
    
    const userGuild = req.session.user.guilds.find(g => g.id === guildId);
    if (!userGuild || !userGuild.isAdmin) {
      return res.status(403).json({ error: 'No admin access' });
    }
    
    try {
      const { data: items } = await supabase
        .from('shop_items')
        .select('*')
        .eq('guild_id', guildId)
        .order('created_at', { ascending: false });
      
      res.json({ items: items || [] });
    } catch (error) {
      console.error('Failed to fetch shop items:', error);
      res.status(500).json({ error: 'Failed to fetch shop items' });
    }
  });
  
  app.post('/api/guild/:guildId/shop', async (req, res) => {
    if (!supabase) {
      return res.status(503).json({ error: 'Database not available' });
    }
    
    const userId = req.session.user?.id;
    if (!userId) {
      return res.status(401).json({ error: 'Not authenticated' });
    }
    
    const { guildId } = req.params;
    
    const userGuild = req.session.user.guilds.find(g => g.id === guildId);
    if (!userGuild || !userGuild.isAdmin) {
      return res.status(403).json({ error: 'No admin access' });
    }
    
    const { name, item_type, description, price, stock, level_required, prestige_required, enabled, category, item_data } = req.body;
    
    try {
      const itemData = {
        guild_id: guildId,
        name,
        item_type: item_type || 'cosmetic',
        description: description || null,
        category: category || null,
        price: price || 100,
        stock: stock || null,
        item_data: item_data || null,
        level_required: level_required || 0,
        prestige_required: prestige_required || 0,
        enabled: enabled !== false,
        created_at: new Date().toISOString()
      };
      
      const { error } = await supabase.from('shop_items').insert(itemData);
      
      if (error) throw error;
      
      res.json({ success: true });
    } catch (error) {
      console.error('Failed to create shop item:', error);
      res.status(500).json({ error: 'Failed to create shop item', details: error.message });
    }
  });
  
  app.put('/api/guild/:guildId/shop/:itemId', async (req, res) => {
    if (!supabase) {
      return res.status(503).json({ error: 'Database not available' });
    }
    
    const userId = req.session.user?.id;
    if (!userId) {
      return res.status(401).json({ error: 'Not authenticated' });
    }
    
    const { guildId, itemId } = req.params;
    
    const userGuild = req.session.user.guilds.find(g => g.id === guildId);
    if (!userGuild || !userGuild.isAdmin) {
      return res.status(403).json({ error: 'No admin access' });
    }
    
    const { name, item_type, description, price, stock, level_required, prestige_required, enabled, category, item_data } = req.body;
    
    try {
      const { error } = await supabase
        .from('shop_items')
        .update({
          name,
          item_type: item_type || 'cosmetic',
          description: description || null,
          category: category || null,
          price: price || 100,
          stock: stock || null,
          item_data: item_data || null,
          level_required: level_required || 0,
          prestige_required: prestige_required || 0,
          enabled: enabled !== false,
          updated_at: new Date().toISOString()
        })
        .eq('id', itemId)
        .eq('guild_id', guildId);
      
      if (error) throw error;
      
      res.json({ success: true });
    } catch (error) {
      console.error('Failed to update shop item:', error);
      res.status(500).json({ error: 'Failed to update shop item', details: error.message });
    }
  });
  
  app.delete('/api/guild/:guildId/shop/:itemId', async (req, res) => {
    if (!supabase) {
      return res.status(503).json({ error: 'Database not available' });
    }
    
    const userId = req.session.user?.id;
    if (!userId) {
      return res.status(401).json({ error: 'Not authenticated' });
    }
    
    const { guildId, itemId } = req.params;
    
    const userGuild = req.session.user.guilds.find(g => g.id === guildId);
    if (!userGuild || !userGuild.isAdmin) {
      return res.status(403).json({ error: 'No admin access' });
    }
    
    try {
      const { error } = await supabase
        .from('shop_items')
        .delete()
        .eq('id', itemId)
        .eq('guild_id', guildId);
      
      if (error) throw error;
      
      res.json({ success: true });
    } catch (error) {
      console.error('Failed to delete shop item:', error);
      res.status(500).json({ error: 'Failed to delete shop item' });
    }
  });
  
  // ============ FEDERATION API ============
  
  app.get('/api/federation/stats', async (req, res) => {
    if (!supabase) {
      return res.status(503).json({ error: 'Database not available' });
    }
    
    try {
      const [servers, bans, applications] = await Promise.all([
        supabase.from('federation_servers').select('id', { count: 'exact' }).eq('status', 'approved'),
        supabase.from('federation_bans').select('id', { count: 'exact' }).eq('active', true),
        supabase.from('federation_applications').select('id', { count: 'exact' }).eq('status', 'pending')
      ]);
      
      res.json({
        totalServers: servers.count || 0,
        activeBans: bans.count || 0,
        pendingApplications: applications.count || 0
      });
    } catch (error) {
      res.status(500).json({ error: 'Failed to fetch stats' });
    }
  });
  
  app.get('/api/federation/bans', async (req, res) => {
    if (!supabase) {
      return res.status(503).json({ error: 'Database not available' });
    }
    
    const { limit = 50, severity } = req.query;
    
    try {
      let query = supabase
        .from('federation_bans')
        .select('*')
        .eq('active', true)
        .order('created_at', { ascending: false })
        .limit(parseInt(limit));
      
      if (severity) {
        query = query.eq('severity', severity);
      }
      
      const { data: bans } = await query;
      res.json({ bans: bans || [] });
    } catch (error) {
      res.status(500).json({ error: 'Failed to fetch bans' });
    }
  });
  
  app.get('/api/federation/servers', async (req, res) => {
    if (!supabase) {
      return res.status(503).json({ error: 'Database not available' });
    }
    
    try {
      const { data: servers } = await supabase
        .from('federation_servers')
        .select('*')
        .eq('status', 'approved')
        .order('member_count', { ascending: false });
      
      res.json({ servers: servers || [] });
    } catch (error) {
      res.status(500).json({ error: 'Failed to fetch servers' });
    }
  });
  
  app.get('/api/federation/applications', async (req, res) => {
    if (!supabase) {
      return res.status(503).json({ error: 'Database not available' });
    }
    
    const userId = req.session.user?.id;
    if (!userId) {
      return res.status(401).json({ error: 'Not authenticated' });
    }
    
    try {
      const { data: applications } = await supabase
        .from('federation_applications')
        .select('*')
        .order('created_at', { ascending: false });
      
      res.json({ applications: applications || [] });
    } catch (error) {
      res.status(500).json({ error: 'Failed to fetch applications' });
    }
  });
  
  app.post('/api/federation/applications/:appId/approve', async (req, res) => {
    if (!supabase) {
      return res.status(503).json({ error: 'Database not available' });
    }
    
    const userId = req.session.user?.id;
    if (!userId) {
      return res.status(401).json({ error: 'Not authenticated' });
    }
    
    const { appId } = req.params;
    
    try {
      const { data: app } = await supabase
        .from('federation_applications')
        .select('*')
        .eq('id', appId)
        .maybeSingle();
      
      if (!app) {
        return res.status(404).json({ error: 'Application not found' });
      }
      
      await supabase.from('federation_applications').update({
        status: 'approved',
        reviewed_by: userId,
        reviewed_at: new Date().toISOString()
      }).eq('id', appId);
      
      await supabase.from('federation_servers').insert({
        guild_id: app.guild_id,
        guild_name: app.guild_name,
        guild_icon: app.guild_icon,
        description: app.description,
        category: app.category,
        member_count: app.member_count,
        owner_id: app.admin_id,
        status: 'approved',
        treaty_accepted: true,
        treaty_accepted_at: new Date().toISOString()
      });
      
      res.json({ success: true });
    } catch (error) {
      console.error('Failed to approve application:', error);
      res.status(500).json({ error: 'Failed to approve application' });
    }
  });
  
  app.post('/api/federation/applications/:appId/reject', async (req, res) => {
    if (!supabase) {
      return res.status(503).json({ error: 'Database not available' });
    }
    
    const userId = req.session.user?.id;
    if (!userId) {
      return res.status(401).json({ error: 'Not authenticated' });
    }
    
    const { appId } = req.params;
    const { reason } = req.body;
    
    try {
      await supabase.from('federation_applications').update({
        status: 'rejected',
        reviewed_by: userId,
        reviewed_at: new Date().toISOString(),
        rejection_reason: reason || 'No reason provided'
      }).eq('id', appId);
      
      res.json({ success: true });
    } catch (error) {
      res.status(500).json({ error: 'Failed to reject application' });
    }
  });
  
  app.get('/api/federation/leaderboard', async (req, res) => {
    if (!supabase) {
      return res.status(503).json({ error: 'Database not available' });
    }
    
    const { limit = 50 } = req.query;
    
    try {
      const { data: leaders } = await supabase
        .from('federation_reputation')
        .select('*')
        .order('reputation_score', { ascending: false })
        .limit(parseInt(limit));
      
      res.json({ leaderboard: leaders || [] });
    } catch (error) {
      res.status(500).json({ error: 'Failed to fetch leaderboard' });
    }
  });
  
  // ============ STRIPE PAYMENT API ============
  
  app.post('/api/stripe/create-checkout', async (req, res) => {
    if (!stripe) {
      return res.status(503).json({ error: 'Stripe not configured' });
    }
    
    const userId = req.session.user?.id;
    if (!userId) {
      return res.status(401).json({ error: 'Not authenticated' });
    }
    
    const { guildId, planType } = req.body;
    
    if (!guildId || !planType) {
      return res.status(400).json({ error: 'Missing guildId or planType' });
    }
    
    const userGuild = req.session.user.guilds?.find(g => g.id === guildId);
    if (!userGuild || !userGuild.isAdmin) {
      return res.status(403).json({ error: 'Must be server admin to purchase' });
    }
    
    try {
      const prices = {
        premium: {
          amount: 5000,
          name: 'Federation Premium',
          description: 'Full protection from all ban severity levels - auto-kick for all threats',
          recurring: { interval: 'month' }
        },
        featured: {
          amount: 20000,
          name: 'Featured Server Slot',
          description: 'Cross-promotion across all federation servers for 1 week',
          recurring: { interval: 'week' }
        }
      };
      
      const plan = prices[planType];
      if (!plan) {
        return res.status(400).json({ error: 'Invalid plan type' });
      }
      
      const session = await stripe.checkout.sessions.create({
        payment_method_types: ['card'],
        mode: 'subscription',
        line_items: [{
          price_data: {
            currency: 'usd',
            product_data: {
              name: plan.name,
              description: plan.description
            },
            unit_amount: plan.amount,
            recurring: plan.recurring
          },
          quantity: 1
        }],
        metadata: {
          guild_id: guildId,
          user_id: userId,
          plan_type: planType
        },
        success_url: `${BASE_URL}/federation?success=true&plan=${planType}`,
        cancel_url: `${BASE_URL}/federation?canceled=true`
      });
      
      res.json({ url: session.url });
    } catch (error) {
      console.error('Stripe checkout error:', error);
      res.status(500).json({ error: 'Failed to create checkout session' });
    }
  });
  
  app.get('/api/federation/subscription/:guildId', async (req, res) => {
    if (!supabase) {
      return res.status(503).json({ error: 'Database not available' });
    }
    
    const { guildId } = req.params;
    
    try {
      const { data: server } = await supabase
        .from('federation_servers')
        .select('tier, subscription_status')
        .eq('guild_id', guildId)
        .maybeSingle();
      
      const { data: featured } = await supabase
        .from('federation_featured')
        .select('active, expires_at')
        .eq('guild_id', guildId)
        .eq('active', true)
        .maybeSingle();
      
      res.json({
        tier: server?.tier || 'free',
        subscriptionStatus: server?.subscription_status || null,
        featured: featured?.active || false,
        featuredExpiresAt: featured?.expires_at || null
      });
    } catch (error) {
      res.status(500).json({ error: 'Failed to fetch subscription' });
    }
  });
  
  // Moderation API Endpoints
  app.get('/api/guild/:guildId/moderation/stats', async (req, res) => {
    if (!supabase) return res.status(503).json({ error: 'Database not available' });
    
    const userId = req.session.user?.id;
    if (!userId) return res.status(401).json({ error: 'Not authenticated' });
    
    const { guildId } = req.params;
    const userGuild = req.session.user.guilds?.find(g => g.id === guildId);
    if (!userGuild?.isAdmin) return res.status(403).json({ error: 'No admin access' });
    
    try {
      const [warningsRes, bansRes, actionsRes] = await Promise.all([
        supabase.from('warnings').select('*', { count: 'exact', head: true }).eq('guild_id', guildId),
        supabase.from('mod_actions').select('*', { count: 'exact', head: true }).eq('guild_id', guildId).eq('action_type', 'ban'),
        supabase.from('mod_actions').select('*', { count: 'exact', head: true }).eq('guild_id', guildId).gte('created_at', new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString())
      ]);
      
      res.json({
        totalWarnings: warningsRes.count || 0,
        activeBans: bansRes.count || 0,
        recentActions: actionsRes.count || 0
      });
    } catch (error) {
      res.status(500).json({ error: 'Failed to fetch stats' });
    }
  });
  
  app.get('/api/guild/:guildId/moderation/warnings', async (req, res) => {
    if (!supabase) return res.status(503).json({ error: 'Database not available' });
    
    const userId = req.session.user?.id;
    if (!userId) return res.status(401).json({ error: 'Not authenticated' });
    
    const { guildId } = req.params;
    const userGuild = req.session.user.guilds?.find(g => g.id === guildId);
    if (!userGuild?.isAdmin) return res.status(403).json({ error: 'No admin access' });
    
    try {
      const { data: warnings } = await supabase
        .from('warnings')
        .select('*')
        .eq('guild_id', guildId)
        .order('created_at', { ascending: false })
        .limit(100);
      
      res.json({ warnings: warnings || [] });
    } catch (error) {
      res.status(500).json({ error: 'Failed to fetch warnings' });
    }
  });
  
  app.delete('/api/guild/:guildId/moderation/warnings/:warningId', async (req, res) => {
    if (!supabase) return res.status(503).json({ error: 'Database not available' });
    
    const userId = req.session.user?.id;
    if (!userId) return res.status(401).json({ error: 'Not authenticated' });
    
    const { guildId, warningId } = req.params;
    const userGuild = req.session.user.guilds?.find(g => g.id === guildId);
    if (!userGuild?.isAdmin) return res.status(403).json({ error: 'No admin access' });
    
    try {
      const { error } = await supabase
        .from('warnings')
        .delete()
        .eq('id', warningId)
        .eq('guild_id', guildId);
      
      if (error) throw error;
      res.json({ success: true });
    } catch (error) {
      res.status(500).json({ error: 'Failed to delete warning' });
    }
  });
  
  app.get('/api/guild/:guildId/moderation/bans', async (req, res) => {
    if (!supabase) return res.status(503).json({ error: 'Database not available' });
    
    const userId = req.session.user?.id;
    if (!userId) return res.status(401).json({ error: 'Not authenticated' });
    
    const { guildId } = req.params;
    const userGuild = req.session.user.guilds?.find(g => g.id === guildId);
    if (!userGuild?.isAdmin) return res.status(403).json({ error: 'No admin access' });
    
    try {
      const { data: bans } = await supabase
        .from('mod_actions')
        .select('*')
        .eq('guild_id', guildId)
        .eq('action_type', 'ban')
        .order('created_at', { ascending: false })
        .limit(100);
      
      res.json({ bans: bans || [] });
    } catch (error) {
      res.status(500).json({ error: 'Failed to fetch bans' });
    }
  });
  
  app.get('/api/guild/:guildId/moderation/activity', async (req, res) => {
    if (!supabase) return res.status(503).json({ error: 'Database not available' });
    
    const userId = req.session.user?.id;
    if (!userId) return res.status(401).json({ error: 'Not authenticated' });
    
    const { guildId } = req.params;
    const userGuild = req.session.user.guilds?.find(g => g.id === guildId);
    if (!userGuild?.isAdmin) return res.status(403).json({ error: 'No admin access' });
    
    try {
      const { data: activity } = await supabase
        .from('mod_actions')
        .select('*')
        .eq('guild_id', guildId)
        .order('created_at', { ascending: false })
        .limit(50);
      
      res.json({ activity: activity || [] });
    } catch (error) {
      res.status(500).json({ error: 'Failed to fetch activity' });
    }
  });
  
  app.get('/api/guild/:guildId/moderation/search', async (req, res) => {
    if (!supabase) return res.status(503).json({ error: 'Database not available' });
    
    const userId = req.session.user?.id;
    if (!userId) return res.status(401).json({ error: 'Not authenticated' });
    
    const { guildId } = req.params;
    const { q } = req.query;
    const userGuild = req.session.user.guilds?.find(g => g.id === guildId);
    if (!userGuild?.isAdmin) return res.status(403).json({ error: 'No admin access' });
    
    if (!q) return res.json({ results: [] });
    
    try {
      const { data: warnings } = await supabase
        .from('warnings')
        .select('user_id, username')
        .eq('guild_id', guildId)
        .or(`user_id.eq.${q},username.ilike.%${q}%`)
        .limit(20);
      
      const userMap = new Map();
      (warnings || []).forEach(w => {
        if (!userMap.has(w.user_id)) {
          userMap.set(w.user_id, { user_id: w.user_id, username: w.username, warnings_count: 0, is_banned: false });
        }
        userMap.get(w.user_id).warnings_count++;
      });
      
      const { data: bans } = await supabase
        .from('mod_actions')
        .select('target_id')
        .eq('guild_id', guildId)
        .eq('action_type', 'ban');
      
      const bannedIds = new Set((bans || []).map(b => b.target_id));
      userMap.forEach(u => { u.is_banned = bannedIds.has(u.user_id); });
      
      res.json({ results: Array.from(userMap.values()) });
    } catch (error) {
      res.status(500).json({ error: 'Search failed' });
    }
  });
  
  // Analytics API Endpoints
  app.get('/api/guild/:guildId/analytics/stats', async (req, res) => {
    if (!supabase) return res.status(503).json({ error: 'Database not available' });
    
    const userId = req.session.user?.id;
    if (!userId) return res.status(401).json({ error: 'Not authenticated' });
    
    const { guildId } = req.params;
    const userGuild = req.session.user.guilds?.find(g => g.id === guildId);
    if (!userGuild?.isAdmin) return res.status(403).json({ error: 'No admin access' });
    
    const today = new Date();
    today.setHours(0, 0, 0, 0);
    const weekAgo = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000);
    
    try {
      const [messagesRes, activeRes, xpRes, commandsRes] = await Promise.all([
        supabase.from('message_logs').select('*', { count: 'exact', head: true }).eq('guild_id', guildId).gte('created_at', today.toISOString()),
        supabase.from('user_stats').select('*', { count: 'exact', head: true }).eq('guild_id', guildId).gte('last_active', weekAgo.toISOString()),
        supabase.from('xp_logs').select('xp_amount').eq('guild_id', guildId).gte('created_at', today.toISOString()),
        supabase.from('command_logs').select('*', { count: 'exact', head: true }).eq('guild_id', guildId).gte('created_at', today.toISOString())
      ]);
      
      const xpToday = (xpRes.data || []).reduce((sum, r) => sum + (r.xp_amount || 0), 0);
      
      res.json({
        messagesToday: messagesRes.count || 0,
        activeUsers: activeRes.count || 0,
        xpToday,
        commandsUsed: commandsRes.count || 0
      });
    } catch (error) {
      res.json({ messagesToday: 0, activeUsers: 0, xpToday: 0, commandsUsed: 0 });
    }
  });
  
  app.get('/api/guild/:guildId/analytics/activity', async (req, res) => {
    if (!supabase) return res.status(503).json({ error: 'Database not available' });
    
    const userId = req.session.user?.id;
    if (!userId) return res.status(401).json({ error: 'Not authenticated' });
    
    const { guildId } = req.params;
    const userGuild = req.session.user.guilds?.find(g => g.id === guildId);
    if (!userGuild?.isAdmin) return res.status(403).json({ error: 'No admin access' });
    
    try {
      const days = [];
      const dayNames = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
      
      for (let i = 6; i >= 0; i--) {
        const date = new Date();
        date.setDate(date.getDate() - i);
        date.setHours(0, 0, 0, 0);
        
        const nextDate = new Date(date);
        nextDate.setDate(nextDate.getDate() + 1);
        
        const { count } = await supabase
          .from('message_logs')
          .select('*', { count: 'exact', head: true })
          .eq('guild_id', guildId)
          .gte('created_at', date.toISOString())
          .lt('created_at', nextDate.toISOString());
        
        days.push({
          label: dayNames[date.getDay()],
          messages: count || 0
        });
      }
      
      res.json({ days });
    } catch (error) {
      res.json({ days: [] });
    }
  });
  
  app.get('/api/guild/:guildId/analytics/top-earners', async (req, res) => {
    if (!supabase) return res.status(503).json({ error: 'Database not available' });
    
    const userId = req.session.user?.id;
    if (!userId) return res.status(401).json({ error: 'Not authenticated' });
    
    const { guildId } = req.params;
    const userGuild = req.session.user.guilds?.find(g => g.id === guildId);
    if (!userGuild?.isAdmin) return res.status(403).json({ error: 'No admin access' });
    
    const today = new Date();
    today.setHours(0, 0, 0, 0);
    
    try {
      const { data } = await supabase
        .from('xp_logs')
        .select('user_id, xp_amount')
        .eq('guild_id', guildId)
        .gte('created_at', today.toISOString());
      
      const userXp = new Map();
      (data || []).forEach(r => {
        userXp.set(r.user_id, (userXp.get(r.user_id) || 0) + (r.xp_amount || 0));
      });
      
      const earners = Array.from(userXp.entries())
        .map(([user_id, xp_earned]) => ({ user_id, xp_earned }))
        .sort((a, b) => b.xp_earned - a.xp_earned)
        .slice(0, 10);
      
      res.json({ earners });
    } catch (error) {
      res.json({ earners: [] });
    }
  });
  
  app.get('/api/guild/:guildId/analytics/top-channels', async (req, res) => {
    if (!supabase) return res.status(503).json({ error: 'Database not available' });
    
    const userId = req.session.user?.id;
    if (!userId) return res.status(401).json({ error: 'Not authenticated' });
    
    const { guildId } = req.params;
    const userGuild = req.session.user.guilds?.find(g => g.id === guildId);
    if (!userGuild?.isAdmin) return res.status(403).json({ error: 'No admin access' });
    
    const today = new Date();
    today.setHours(0, 0, 0, 0);
    
    try {
      const { data } = await supabase
        .from('message_logs')
        .select('channel_id, channel_name')
        .eq('guild_id', guildId)
        .gte('created_at', today.toISOString());
      
      const channelCounts = new Map();
      (data || []).forEach(r => {
        const key = r.channel_id;
        if (!channelCounts.has(key)) {
          channelCounts.set(key, { channel_id: r.channel_id, channel_name: r.channel_name, message_count: 0 });
        }
        channelCounts.get(key).message_count++;
      });
      
      const channels = Array.from(channelCounts.values())
        .sort((a, b) => b.message_count - a.message_count)
        .slice(0, 10);
      
      res.json({ channels });
    } catch (error) {
      res.json({ channels: [] });
    }
  });
  
  app.get('/api/guild/:guildId/analytics/commands', async (req, res) => {
    if (!supabase) return res.status(503).json({ error: 'Database not available' });
    
    const userId = req.session.user?.id;
    if (!userId) return res.status(401).json({ error: 'Not authenticated' });
    
    const { guildId } = req.params;
    const userGuild = req.session.user.guilds?.find(g => g.id === guildId);
    if (!userGuild?.isAdmin) return res.status(403).json({ error: 'No admin access' });
    
    try {
      const { data } = await supabase
        .from('command_logs')
        .select('command_name')
        .eq('guild_id', guildId);
      
      const commandCounts = new Map();
      (data || []).forEach(r => {
        commandCounts.set(r.command_name, (commandCounts.get(r.command_name) || 0) + 1);
      });
      
      const commands = Array.from(commandCounts.entries())
        .map(([command_name, use_count]) => ({ command_name, use_count }))
        .sort((a, b) => b.use_count - a.use_count)
        .slice(0, 10);
      
      res.json({ commands });
    } catch (error) {
      res.json({ commands: [] });
    }
  });

  // Titles API endpoints
  app.get('/api/guild/:guildId/titles', async (req, res) => {
    if (!supabase) return res.status(503).json({ error: 'Database not available' });
    
    const userId = req.session.user?.id;
    if (!userId) return res.status(401).json({ error: 'Not authenticated' });
    
    const { guildId } = req.params;
    
    try {
      // Get user's link
      const { data: link } = await supabase
        .from('discord_links')
        .select('user_id')
        .eq('discord_id', userId)
        .maybeSingle();
      
      if (!link) {
        return res.json({ titles: [], activeTitle: null });
      }
      
      // Get user's inventory items that are titles
      const { data: inventory } = await supabase
        .from('user_inventory')
        .select(`
          id,
          item_id,
          purchased_at,
          is_active,
          shop_items!inner (id, name, description, item_type)
        `)
        .eq('user_id', link.user_id)
        .eq('guild_id', guildId)
        .eq('shop_items.item_type', 'title');
      
      const titles = (inventory || []).map(inv => ({
        id: inv.id,
        item_id: inv.item_id,
        name: inv.shop_items?.name || 'Unknown Title',
        description: inv.shop_items?.description || '',
        purchased_at: inv.purchased_at,
        is_active: inv.is_active === true
      }));
      
      const activeTitle = titles.find(t => t.is_active) || null;
      
      res.json({ titles, activeTitle });
    } catch (error) {
      console.error('Failed to fetch titles:', error);
      res.status(500).json({ error: 'Failed to load titles', titles: [], activeTitle: null });
    }
  });
  
  app.post('/api/guild/:guildId/titles/active', async (req, res) => {
    if (!supabase) return res.status(503).json({ error: 'Database not available' });
    
    const userId = req.session.user?.id;
    if (!userId) return res.status(401).json({ error: 'Not authenticated' });
    
    const { guildId } = req.params;
    const { title_id } = req.body;
    
    if (!title_id) {
      return res.status(400).json({ error: 'Title ID required' });
    }
    
    try {
      const { data: link } = await supabase
        .from('discord_links')
        .select('user_id')
        .eq('discord_id', userId)
        .maybeSingle();
      
      if (!link) {
        return res.status(400).json({ error: 'Account not linked' });
      }
      
      // Get all title-type inventory items and clear their active status
      const { data: titleItems } = await supabase
        .from('user_inventory')
        .select('id, shop_items!inner(item_type)')
        .eq('user_id', link.user_id)
        .eq('guild_id', guildId)
        .eq('shop_items.item_type', 'title');
      
      if (titleItems && titleItems.length > 0) {
        const titleIds = titleItems.map(t => t.id);
        await supabase
          .from('user_inventory')
          .update({ is_active: false })
          .in('id', titleIds);
      }
      
      // Set the selected title as active
      const { error } = await supabase
        .from('user_inventory')
        .update({ is_active: true })
        .eq('id', title_id)
        .eq('user_id', link.user_id)
        .eq('guild_id', guildId);
      
      if (error) throw error;
      
      res.json({ success: true });
    } catch (error) {
      console.error('Failed to set active title:', error);
      res.status(500).json({ error: 'Failed to set title' });
    }
  });
  
  app.delete('/api/guild/:guildId/titles/active', async (req, res) => {
    if (!supabase) return res.status(503).json({ error: 'Database not available' });
    
    const userId = req.session.user?.id;
    if (!userId) return res.status(401).json({ error: 'Not authenticated' });
    
    const { guildId } = req.params;
    
    try {
      const { data: link } = await supabase
        .from('discord_links')
        .select('user_id')
        .eq('discord_id', userId)
        .maybeSingle();
      
      if (!link) {
        return res.status(400).json({ error: 'Account not linked' });
      }
      
      // Get all title-type inventory items and clear their active status
      const { data: titleItems } = await supabase
        .from('user_inventory')
        .select('id, shop_items!inner(item_type)')
        .eq('user_id', link.user_id)
        .eq('guild_id', guildId)
        .eq('shop_items.item_type', 'title');
      
      if (titleItems && titleItems.length > 0) {
        const titleIds = titleItems.map(t => t.id);
        await supabase
          .from('user_inventory')
          .update({ is_active: false })
          .in('id', titleIds);
      }
      
      res.json({ success: true });
    } catch (error) {
      console.error('Failed to clear active title:', error);
      res.status(500).json({ error: 'Failed to clear title' });
    }
  });

  // Coins API endpoints
  app.get('/api/guild/:guildId/coins', async (req, res) => {
    if (!supabase) return res.status(503).json({ error: 'Database not available' });
    
    const userId = req.session.user?.id;
    if (!userId) return res.status(401).json({ error: 'Not authenticated' });
    
    const { guildId } = req.params;
    
    try {
      const { data: link } = await supabase
        .from('discord_links')
        .select('user_id')
        .eq('discord_id', userId)
        .maybeSingle();
      
      if (!link) {
        return res.json({ coins: 0, coinName: 'Coins' });
      }
      
      const { data: stats } = await supabase
        .from('user_stats')
        .select('coins')
        .eq('user_id', link.user_id)
        .eq('guild_id', guildId)
        .maybeSingle();
      
      const { data: config } = await supabase
        .from('xp_config')
        .select('coin_name')
        .eq('guild_id', guildId)
        .maybeSingle();
      
      res.json({ 
        coins: stats?.coins || 0, 
        coinName: config?.coin_name || 'Coins' 
      });
    } catch (error) {
      console.error('Failed to fetch coins:', error);
      res.status(500).json({ error: 'Failed to load coins' });
    }
  });
  
  app.get('/api/guild/:guildId/coins/config', async (req, res) => {
    if (!supabase) return res.status(503).json({ error: 'Database not available' });
    
    const userId = req.session.user?.id;
    if (!userId) return res.status(401).json({ error: 'Not authenticated' });
    
    const { guildId } = req.params;
    
    const userGuild = req.session.user.guilds.find(g => g.id === guildId);
    if (!userGuild || !userGuild.isAdmin) {
      return res.status(403).json({ error: 'No admin access' });
    }
    
    try {
      const { data: config } = await supabase
        .from('xp_config')
        .select('coins_enabled, message_coins, daily_coins, coin_name')
        .eq('guild_id', guildId)
        .maybeSingle();
      
      res.json({ 
        config: config || { coins_enabled: true, message_coins: 1, daily_coins: 50, coin_name: 'Coins' } 
      });
    } catch (error) {
      console.error('Failed to fetch coin config:', error);
      res.status(500).json({ error: 'Failed to load coin config' });
    }
  });
  
  app.post('/api/guild/:guildId/coins/config', async (req, res) => {
    if (!supabase) return res.status(503).json({ error: 'Database not available' });
    
    const userId = req.session.user?.id;
    if (!userId) return res.status(401).json({ error: 'Not authenticated' });
    
    const { guildId } = req.params;
    
    const userGuild = req.session.user.guilds.find(g => g.id === guildId);
    if (!userGuild || !userGuild.isAdmin) {
      return res.status(403).json({ error: 'No admin access' });
    }
    
    const { coins_enabled, message_coins, daily_coins, coin_name } = req.body;
    
    // Validate inputs
    const validMessageCoins = Math.max(0, Math.min(100, parseInt(message_coins) || 1));
    const validDailyCoins = Math.max(0, Math.min(1000, parseInt(daily_coins) || 50));
    const validCoinName = (coin_name || 'Coins').toString().substring(0, 32);
    const validCoinsEnabled = coins_enabled === true;
    
    try {
      const { data: existing } = await supabase
        .from('xp_config')
        .select('guild_id')
        .eq('guild_id', guildId)
        .maybeSingle();
      
      const coinData = {
        coins_enabled: validCoinsEnabled,
        message_coins: validMessageCoins,
        daily_coins: validDailyCoins,
        coin_name: validCoinName,
        updated_at: new Date().toISOString()
      };
      
      if (existing) {
        const { error } = await supabase
          .from('xp_config')
          .update(coinData)
          .eq('guild_id', guildId);
        if (error) throw error;
      } else {
        const { error } = await supabase
          .from('xp_config')
          .insert({ guild_id: guildId, ...coinData });
        if (error) throw error;
      }
      
      res.json({ success: true });
    } catch (error) {
      console.error('Failed to save coin config:', error);
      res.status(500).json({ error: 'Failed to save coin settings' });
    }
  });
  
  app.get('/api/guild/:guildId/coins/leaderboard', async (req, res) => {
    if (!supabase) return res.status(503).json({ error: 'Database not available' });
    
    const { guildId } = req.params;
    const { limit = 50 } = req.query;
    
    try {
      const { data: leaderboard } = await supabase
        .from('user_stats')
        .select('user_id, coins')
        .eq('guild_id', guildId)
        .gt('coins', 0)
        .order('coins', { ascending: false })
        .limit(parseInt(limit));
      
      const { data: config } = await supabase
        .from('xp_config')
        .select('coin_name')
        .eq('guild_id', guildId)
        .maybeSingle();
      
      res.json({ 
        leaderboard: leaderboard || [], 
        coinName: config?.coin_name || 'Coins' 
      });
    } catch (error) {
      console.error('Failed to fetch coin leaderboard:', error);
      res.status(500).json({ error: 'Failed to load leaderboard' });
    }
  });

  app.get('/health', (req, res) => {
    res.json({ 
      status: 'ok', 
      bot: discordClient.user ? 'online' : 'offline',
      uptime: process.uptime()
    });
  });
  
  app.get('/api/bot-stats', async (req, res) => {
    try {
      const guilds = discordClient.guilds?.cache?.size || 0;
      let users = 0;
      
      if (discordClient.guilds?.cache) {
        discordClient.guilds.cache.forEach(guild => {
          users += guild.memberCount || 0;
        });
      }
      
      let linkedProfiles = 0;
      if (supabase) {
        const { count } = await supabase
          .from('discord_links')
          .select('*', { count: 'exact', head: true });
        linkedProfiles = count || 0;
      }
      
      res.json({
        guilds,
        users,
        linkedProfiles,
        commands: 66,
        uptime: process.uptime()
      });
    } catch (error) {
      res.json({ guilds: 0, users: 0, linkedProfiles: 0, commands: 66 });
    }
  });
  
  app.get('/federation', (req, res) => {
    res.sendFile(path.join(__dirname, '../public/federation.html'));
  });
  
  app.get('/pricing', (req, res) => {
    res.sendFile(path.join(__dirname, '../public/pricing.html'));
  });
  
  app.get('/dashboard', (req, res) => {
    res.sendFile(path.join(__dirname, '../public/dashboard.html'));
  });
  
  app.get('/leaderboard', (req, res) => {
    res.redirect('/dashboard?page=leaderboard');
  });
  
  app.get('/features', (req, res) => {
    res.sendFile(path.join(__dirname, '../public/features.html'));
  });
  
  app.get('/commands', (req, res) => {
    res.sendFile(path.join(__dirname, '../public/commands.html'));
  });
  
  app.get('/', (req, res) => {
    res.sendFile(path.join(__dirname, '../public/index.html'));
  });
  
  // Catch-all route for SPA - use middleware instead of wildcard
  app.use((req, res, next) => {
    if (req.method === 'GET' && !req.path.startsWith('/api/')) {
      res.sendFile(path.join(__dirname, '../public/index.html'));
    } else if (req.path.startsWith('/api/')) {
      res.status(404).json({ error: 'API endpoint not found' });
    } else {
      next();
    }
  });
  
  return app;
}

module.exports = { createWebServer };
