const { checkMilestoneRoles, calculateLevel, updateUserStats, getUserStats, updatePeriodicXp, updateQuestProgress } = require('./xpTracker');
const { checkAchievements } = require('../commands/achievements');

const reactionCooldowns = new Map();
const xpConfigCache = new Map();
const CACHE_TTL = 60000;

module.exports = {
  name: 'messageReactionAdd',
  
  async execute(reaction, user, client, supabase) {
    if (!supabase) return;
    if (user.bot) return;
    if (!reaction.message.guild) return;

    if (reaction.partial) {
      try {
        await reaction.fetch();
      } catch (error) {
        console.error('Failed to fetch reaction:', error);
        return;
      }
    }

    const messageAuthor = reaction.message.author;
    if (!messageAuthor || messageAuthor.bot) return;
    if (messageAuthor.id === user.id) return;

    const guildId = reaction.message.guild.id;
    const now = Date.now();

    const config = await getXpConfig(supabase, guildId);
    
    if (!config.xp_enabled) return;
    if (!config.reaction_xp_enabled) return;

    const receiverXp = config.reaction_xp_received || 3;
    const giverXp = config.reaction_xp_given || 1;
    const cooldownMs = (config.reaction_cooldown || 30) * 1000;

    const cooldownKeyGiver = `reaction:giver:${guildId}:${user.id}`;
    const cooldownKeyReceiver = `reaction:receiver:${guildId}:${messageAuthor.id}`;
    const cooldownKeyMessage = `reaction:message:${guildId}:${reaction.message.id}`;

    const lastGiverXp = reactionCooldowns.get(cooldownKeyGiver) || 0;
    const lastReceiverXp = reactionCooldowns.get(cooldownKeyReceiver) || 0;
    const lastMessageXp = reactionCooldowns.get(cooldownKeyMessage) || 0;

    const giverOnCooldown = now - lastGiverXp < cooldownMs;
    const receiverOnCooldown = now - lastReceiverXp < cooldownMs || now - lastMessageXp < cooldownMs;

    try {
      const giverMember = await reaction.message.guild.members.fetch(user.id).catch(() => null);
      const receiverMember = await reaction.message.guild.members.fetch(messageAuthor.id).catch(() => null);

      if (!giverOnCooldown && giverXp > 0) {
        await grantXp(supabase, user.id, giverXp, client, giverMember, config, guildId, 'giver');
        reactionCooldowns.set(cooldownKeyGiver, now);
      }

      if (!receiverOnCooldown && receiverXp > 0) {
        await grantXp(supabase, messageAuthor.id, receiverXp, client, receiverMember, config, guildId, 'receiver');
        reactionCooldowns.set(cooldownKeyReceiver, now);
        reactionCooldowns.set(cooldownKeyMessage, now);
      }
    } catch (error) {
      console.error('Reaction XP tracking error:', error.message);
    }
  }
};

async function grantXp(supabase, discordUserId, xpAmount, client, member, config, guildId, reactionType) {
  const { data: link, error: linkError } = await supabase
    .from('discord_links')
    .select('user_id')
    .eq('discord_id', discordUserId)
    .maybeSingle();

  if (linkError || !link) return;

  const { data: profile, error: profileError } = await supabase
    .from('user_profiles')
    .select('xp, prestige_level, total_xp_earned, daily_streak')
    .eq('id', link.user_id)
    .maybeSingle();

  if (profileError || !profile) return;

  let finalXp = xpAmount;
  const prestige = profile.prestige_level || 0;

  if (member && config) {
    const multiplierRoles = config.multiplier_roles || [];
    let highestMultiplier = 1;
    
    for (const mr of multiplierRoles) {
      if (member.roles?.cache?.has(mr.role_id)) {
        highestMultiplier = Math.max(highestMultiplier, mr.multiplier);
      }
    }
    
    if (member.premiumSince) {
      highestMultiplier = Math.max(highestMultiplier, 1.5);
    }
    
    finalXp = Math.floor(xpAmount * highestMultiplier);
  }

  if (prestige > 0) {
    const prestigeBonus = 1 + (prestige * 0.05);
    finalXp = Math.floor(finalXp * prestigeBonus);
  }

  const currentXp = profile.xp || 0;
  const newXp = currentXp + finalXp;
  const totalEarned = (profile.total_xp_earned || currentXp) + finalXp;

  const oldLevel = calculateLevel(currentXp, config?.level_curve);
  const newLevel = calculateLevel(newXp, config?.level_curve);

  const { error: updateError } = await supabase
    .from('user_profiles')
    .update({ xp: newXp, total_xp_earned: totalEarned })
    .eq('id', link.user_id);

  if (updateError) return;

  if (client.trackXP) {
    client.trackXP(finalXp);
  }

  // Track periodic XP for weekly/monthly leaderboards (false = not a message)
  await updatePeriodicXp(supabase, link.user_id, guildId, discordUserId, finalXp, false);

  // Track reaction stats
  const statIncrement = reactionType === 'giver' 
    ? { reactionsGiven: 1 } 
    : { reactionsReceived: 1 };
  await updateUserStats(supabase, link.user_id, guildId, statIncrement);

  if (member && guildId) {
    await checkMilestoneRoles(member, {
      level: newLevel,
      prestige: prestige,
      totalXp: totalEarned
    }, supabase, guildId, newLevel <= oldLevel);

    // Get updated stats and check achievements
    const stats = await getUserStats(supabase, link.user_id, guildId);
    stats.level = newLevel;
    stats.prestige = prestige;
    stats.totalXp = totalEarned;
    stats.dailyStreak = profile.daily_streak || 0;

    await checkAchievements(link.user_id, member, stats, supabase, guildId, client);

    // Track quest progress for reactions
    if (reactionType === 'giver') {
      await updateQuestProgress(supabase, link.user_id, guildId, 'reactions', 1);
    }
    await updateQuestProgress(supabase, link.user_id, guildId, 'xp_earned', finalXp);
  }
}

async function getXpConfig(supabase, guildId) {
  const now = Date.now();
  const cached = xpConfigCache.get(guildId);
  
  if (cached && (now - cached.timestamp < CACHE_TTL)) {
    return cached.config;
  }

  try {
    const { data, error } = await supabase
      .from('xp_config')
      .select('*')
      .eq('guild_id', guildId)
      .maybeSingle();

    if (error) {
      const defaults = getDefaultConfig();
      xpConfigCache.set(guildId, { config: defaults, timestamp: now });
      return defaults;
    }

    const config = data || getDefaultConfig();
    xpConfigCache.set(guildId, { config, timestamp: now });
    return config;
  } catch (e) {
    return getDefaultConfig();
  }
}

function getDefaultConfig() {
  return {
    message_xp: 5,
    message_cooldown: 60,
    multiplier_roles: [],
    bonus_channels: [],
    level_curve: 'normal',
    xp_enabled: true,
    reaction_xp_enabled: true,
    reaction_xp_received: 3,
    reaction_xp_given: 1,
    reaction_cooldown: 30
  };
}
