// ═══════════════════════════════════════════════════════════════════════════════
// COMPETITION & SOCIAL CONTEST BOT INTEGRATION
// APPEND THIS ENTIRE BLOCK to the END of telegram-bot.js
// (after the draft persistence functions at the very bottom)
//
// This uses all existing telegram-bot.js globals:
//   supabase, db, fmt, edit, send, cb, Markup
//   setState, getState, clearState, updateState, userState
// ═══════════════════════════════════════════════════════════════════════════════

const {
  COMP, platformFee, totalCostOpen, vaeToUsd,
  showCompetitionsMenu, viewCompetition, viewChallenge,
  judgeCompetition, awardWinner,
  reviewChallengeSubmissions, approveChallengeEntry,
  myCompetitions, runCompetitionScheduler,
} = require('./competition_module');

// Thin notify wrapper using existing bot instance
const _notifyComp = async (telegramId, message) => {
  if (!telegramId) return;
  try {
    await bot.telegram.sendMessage(String(telegramId), message, { parse_mode: 'HTML' });
  } catch (e) { /* silent */ }
};

// ─── MENU ─────────────────────────────────────────────────────────────────────
bot.action('competitions_menu', async (ctx) => {
  await cb(ctx);
  await showCompetitionsMenu(ctx, supabase, edit, Markup, fmt);
});

// ─── VIEW ─────────────────────────────────────────────────────────────────────
bot.action(/^comp_view_(.+)$/, async (ctx) => {
  await cb(ctx);
  const user = await db.getUser(ctx.from.id);
  await viewCompetition(ctx, ctx.match[1], supabase, edit, Markup, fmt, user.id);
});

bot.action(/^chal_view_(.+)$/, async (ctx) => {
  await cb(ctx);
  const user = await db.getUser(ctx.from.id);
  await viewChallenge(ctx, ctx.match[1], supabase, edit, Markup, fmt, user.id);
});

// ─── CREATE OPEN COMPETITION ──────────────────────────────────────────────────
bot.action('comp_create', async (ctx) => {
  await cb(ctx);
  const user = await db.getUser(ctx.from.id);
  const minCost = totalCostOpen(COMP.MIN_PRIZE_OPEN);

  if ((user.balance?.available || 0) < minCost) {
    return edit(ctx,
      `❌ <b>Insufficient Balance</b>\n\nTo post a competition you need:\n• Minimum prize: $${vaeToUsd(COMP.MIN_PRIZE_OPEN)}\n• Platform fee (25%): $${vaeToUsd(platformFee(COMP.MIN_PRIZE_OPEN))}\n• Setup fee: $${vaeToUsd(COMP.SETUP_FEE_OPEN)}\n• <b>Minimum total: $${vaeToUsd(minCost)}</b>\n\nYour balance: $${vaeToUsd(user.balance?.available || 0)}`,
      Markup.inlineKeyboard([
        [Markup.button.callback('💳 Add Funds', 'buy_vae')],
        [Markup.button.callback('🔙 Back', 'competitions_menu')],
      ])
    );
  }

  setState(ctx.from.id, {
    action: 'create_competition',
    draft: { title: null, description: null, category: 'other', prize_pool: null, duration_days: null },
  });

  return edit(ctx,
    `🏆 <b>Create Open Competition</b>\n\nWorkers submit their best work. You pick 1 winner who gets 100% of your prize.\n\n💰 <b>Fees:</b>\n• You set the prize (min $50)\n• Platform fee: 25% added on top\n• Setup fee: $25 (non-refundable)\n• Example: $200 prize → you pay $275 total → winner gets $200\n\n<b>Step 1 of 4: What is your competition title?</b>\n<i>E.g. "Design our logo" or "Best product photo"</i>`,
    Markup.inlineKeyboard([[Markup.button.callback('❌ Cancel', 'competitions_menu')]])
  );
});

// ─── CREATE SOCIAL CONTEST ────────────────────────────────────────────────────
bot.action('chal_create', async (ctx) => {
  await cb(ctx);
  setState(ctx.from.id, {
    action: 'create_challenge',
    draft: {
      title: null, description: null, platform: 'TikTok', hashtag: null,
      base_pay_per_post: null, prize_1st: null, prize_2nd: null, prize_3rd: null,
      duration_days: null, requirements: null,
    },
  });

  return edit(ctx,
    `📱 <b>Create Social Media Contest</b>\n\nPeople post on TikTok/Instagram/YouTube about your brand.\nEvery approved post gets base pay. Top 3 by engagement get bonus prizes.\n\n💰 <b>Fees:</b>\n• You set base pay per post (min $3)\n• You set 1st/2nd/3rd bonus prizes\n• Platform fee: 25% on all payouts\n• Setup fee: $49 (charged now, non-refundable)\n• AI content &amp; avatars welcome ✅\n\n<b>Step 1 of 5: What is your contest title?</b>\n<i>E.g. "Show us how you use our product"</i>`,
    Markup.inlineKeyboard([[Markup.button.callback('❌ Cancel', 'competitions_menu')]])
  );
});

// ─── ENTER OPEN COMPETITION (worker) ─────────────────────────────────────────
bot.action(/^comp_enter_(.+)$/, async (ctx) => {
  await cb(ctx);
  const compId = ctx.match[1];
  const user = await db.getUser(ctx.from.id);

  const { data: comp } = await supabase.from('competitions').select('*').eq('id', compId).single();
  if (!comp || comp.status !== 'active') {
    return edit(ctx, '❌ Competition is no longer active.',
      Markup.inlineKeyboard([[Markup.button.callback('🔙 Back', 'competitions_menu')]]));
  }
  if (comp.requester_id === user.id) {
    return edit(ctx, '❌ You cannot enter your own competition.',
      Markup.inlineKeyboard([[Markup.button.callback('🔙 Back', `comp_view_${compId}`)]]));
  }

  const { data: existing } = await supabase.from('competition_entries')
    .select('id').eq('competition_id', compId).eq('user_id', user.id).maybeSingle();
  if (existing) {
    return edit(ctx, '❌ You already submitted an entry for this competition.',
      Markup.inlineKeyboard([[Markup.button.callback('🔙 Back', `comp_view_${compId}`)]]));
  }

  setState(ctx.from.id, { action: 'comp_entry', compId, files: [], userId: user.id });

  return edit(ctx,
    `✍️ <b>Submit Your Entry</b>\n\nCompetition: <b>${fmt.esc(comp.title)}</b>\nPrize: <b>$${vaeToUsd(comp.prize_pool)}</b>\n\n📤 Send your entry now:\n• Text, images, files, or links — all accepted\n• Make it your very best work!\n• One submission per person\n\n<i>Just send your content and it will be submitted automatically.</i>`,
    Markup.inlineKeyboard([[Markup.button.callback('❌ Cancel', `comp_view_${compId}`)]])
  );
});

// ─── ENTER SOCIAL CONTEST (worker) ───────────────────────────────────────────
bot.action(/^chal_enter_(.+)$/, async (ctx) => {
  await cb(ctx);
  const chalId = ctx.match[1];
  const user = await db.getUser(ctx.from.id);

  const { data: chal } = await supabase.from('social_challenges').select('*').eq('id', chalId).single();
  if (!chal || chal.status !== 'active') {
    return edit(ctx, '❌ Contest is no longer active.',
      Markup.inlineKeyboard([[Markup.button.callback('🔙 Back', 'competitions_menu')]]));
  }
  if (chal.requester_id === user.id) {
    return edit(ctx, '❌ You cannot enter your own contest.',
      Markup.inlineKeyboard([[Markup.button.callback('🔙 Back', `chal_view_${chalId}`)]]));
  }

  const { data: existing } = await supabase.from('challenge_entries')
    .select('id').eq('challenge_id', chalId).eq('user_id', user.id).maybeSingle();
  if (existing) {
    return edit(ctx, '❌ You already submitted to this contest.',
      Markup.inlineKeyboard([[Markup.button.callback('🔙 Back', `chal_view_${chalId}`)]]));
  }

  setState(ctx.from.id, { action: 'chal_entry', chalId, userId: user.id });

  const hashMsg = chal.hashtag ? `\nRequired hashtag: <b>${fmt.esc(chal.hashtag)}</b>` : '';
  return edit(ctx,
    `📱 <b>Submit Your Post</b>\n\nContest: <b>${fmt.esc(chal.title)}</b>\nBase pay on approval: <b>$${vaeToUsd(chal.base_pay_per_post)}</b>${hashMsg}\n\n<b>Steps:</b>\n1️⃣ Post your content on ${chal.platform || 'social media'}\n2️⃣ Send your post URL here\n\n🤖 AI content, avatars and characters welcome!\n\n<i>Just send the URL of your live post.</i>`,
    Markup.inlineKeyboard([[Markup.button.callback('❌ Cancel', `chal_view_${chalId}`)]])
  );
});

// ─── JUDGE & AWARD ────────────────────────────────────────────────────────────
bot.action(/^comp_judge_(.+)$/, async (ctx) => {
  await cb(ctx);
  const user = await db.getUser(ctx.from.id);
  await judgeCompetition(ctx, ctx.match[1], supabase, edit, Markup, fmt, user.id);
});

bot.action(/^comp_entries_(.+)$/, async (ctx) => {
  await cb(ctx);
  const user = await db.getUser(ctx.from.id);
  await judgeCompetition(ctx, ctx.match[1], supabase, edit, Markup, fmt, user.id);
});

bot.action(/^comp_award_([0-9a-f-]+)_([0-9a-f-]+)$/i, async (ctx) => {
  await cb(ctx);
  const [, compId, entryId] = ctx.match;
  const user = await db.getUser(ctx.from.id);
  const { data: comp } = await supabase.from('competitions').select('requester_id').eq('id', compId).single();
  if (comp?.requester_id !== user.id) {
    return edit(ctx, '❌ Only the requester can award the prize.',
      Markup.inlineKeyboard([[Markup.button.callback('🔙 Back', 'competitions_menu')]]));
  }
  await awardWinner(ctx, compId, entryId, supabase, edit, Markup, fmt, db, _notifyComp);
});

// ─── REVIEW & APPROVE SOCIAL ──────────────────────────────────────────────────
bot.action(/^chal_review_(.+)$/, async (ctx) => {
  await cb(ctx);
  const user = await db.getUser(ctx.from.id);
  await reviewChallengeSubmissions(ctx, ctx.match[1], supabase, edit, Markup, fmt, user.id);
});

bot.action(/^chal_approve_([0-9a-f-]+)_([0-9a-f-]+)$/i, async (ctx) => {
  await cb(ctx);
  const [, chalId, entryId] = ctx.match;
  const user = await db.getUser(ctx.from.id);
  const { data: chal } = await supabase.from('social_challenges').select('requester_id').eq('id', chalId).single();
  if (chal?.requester_id !== user.id) {
    return edit(ctx, '❌ Only the requester can approve.',
      Markup.inlineKeyboard([[Markup.button.callback('🔙 Back', 'competitions_menu')]]));
  }
  await approveChallengeEntry(ctx, chalId, entryId, supabase, edit, Markup, fmt, db, _notifyComp);
});

bot.action(/^chal_reject_([0-9a-f-]+)_([0-9a-f-]+)$/i, async (ctx) => {
  await cb(ctx);
  const [, chalId, entryId] = ctx.match;
  const user = await db.getUser(ctx.from.id);
  const { data: chal } = await supabase.from('social_challenges').select('requester_id,title').eq('id', chalId).single();
  if (chal?.requester_id !== user.id) {
    return edit(ctx, '❌ Only the requester can reject.',
      Markup.inlineKeyboard([[Markup.button.callback('🔙 Back', 'competitions_menu')]]));
  }
  setState(ctx.from.id, { action: 'chal_reject_reason', chalId, entryId });
  return edit(ctx,
    `❌ <b>Reject Submission</b>\n\nSend a brief reason so the worker can improve.\n<i>E.g. "Missing required hashtag" or "Doesn't match brief"</i>`,
    Markup.inlineKeyboard([[Markup.button.callback('⏭️ Skip reason', `chal_reject_noreason_${chalId}_${entryId}`)]])
  );
});

bot.action(/^chal_reject_noreason_([0-9a-f-]+)_([0-9a-f-]+)$/i, async (ctx) => {
  await cb(ctx);
  const [, chalId, entryId] = ctx.match;
  await supabase.from('challenge_entries').update({ status: 'rejected' }).eq('id', entryId);
  const { data: e } = await supabase.from('challenge_entries')
    .select('user_id,worker:app_users(telegram_id)').eq('id', entryId).single();
  const { data: chal } = await supabase.from('social_challenges').select('title').eq('id', chalId).single();
  if (e?.worker?.telegram_id) {
    await _notifyComp(e.worker.telegram_id,
      `❌ Your submission for "<b>${fmt.esc(chal?.title || '')}</b>" was not approved.\nPlease review the requirements and try again.`
    );
  }
  const user = await db.getUser(ctx.from.id);
  return reviewChallengeSubmissions(ctx, chalId, supabase, edit, Markup, fmt, user.id);
});

// ─── FLAG SUSPICIOUS WINNER ───────────────────────────────────────────────────
bot.action(/^comp_flag_(.+)$/, async (ctx) => {
  await cb(ctx);
  const compId = ctx.match[1];
  const user = await db.getUser(ctx.from.id);
  const { data: myEntry } = await supabase.from('competition_entries')
    .select('id').eq('competition_id', compId).eq('user_id', user.id).maybeSingle();
  if (!myEntry) {
    return edit(ctx, '❌ You must have entered this competition to flag it.',
      Markup.inlineKeyboard([[Markup.button.callback('🔙 Back', 'competitions_menu')]]));
  }
  await supabase.from('competitions')
    .update({ metadata: { flagged: true, flagged_by: user.id, flagged_at: new Date().toISOString() } })
    .eq('id', compId);
  return edit(ctx,
    `🚩 <b>Flagged for Review</b>\n\nThank you. Our team will review within 24 hours.\nIf fraud is confirmed, the prize will be redistributed.`,
    Markup.inlineKeyboard([[Markup.button.callback('🔙 Menu', 'menu')]])
  );
});

// ─── MY COMPETITIONS ──────────────────────────────────────────────────────────
bot.action('my_competitions', async (ctx) => {
  await cb(ctx);
  const user = await db.getUser(ctx.from.id);
  await myCompetitions(ctx, supabase, edit, Markup, fmt, user.id);
});

// ─── CONFIRM POST COMPETITION ─────────────────────────────────────────────────
bot.action('comp_confirm_post', async (ctx) => {
  await cb(ctx);
  const user = await db.getUser(ctx.from.id);
  const state = getState(ctx.from.id);
  const draft = state?.draft;
  if (!draft?.prize_pool || !draft?.title) {
    return edit(ctx, '❌ No competition draft found.',
      Markup.inlineKeyboard([[Markup.button.callback('🔙 Back', 'competitions_menu')]]));
  }

  const total = totalCostOpen(draft.prize_pool);
  const deducted = await db.deductBalance(user.id, total);
  if (!deducted) {
    return edit(ctx, `❌ Insufficient balance. Need $${vaeToUsd(total)}.`,
      Markup.inlineKeyboard([[Markup.button.callback('💳 Add Funds', 'buy_vae')]]));
  }

  await db.recordTransaction(user.id, 'competition_setup', -total, null, `Posted competition: ${draft.title}`);

  const { data: comp } = await supabase.from('competitions').insert({
    requester_id: user.id,
    title: draft.title,
    description: draft.description,
    category: draft.category || 'other',
    prize_pool: draft.prize_pool,
    prize_structure: { '1st': draft.prize_pool },
    setup_fee: COMP.SETUP_FEE_OPEN,
    platform_fee_pct: COMP.PLATFORM_FEE_PCT,
    setup_fee_paid: true,
    min_entries: COMP.MIN_ENTRIES_OPEN,
    winner_deadline_hours: COMP.WINNER_GRACE_HRS,
    deadline: new Date(Date.now() + draft.duration_days * 86400000).toISOString(),
    status: 'active',
    entry_count: 0,
  }).select().single();

  clearState(ctx.from.id);

  return edit(ctx,
    `🏆 <b>Competition Live!</b>\n\n"<b>${fmt.esc(draft.title)}</b>"\n💰 Prize: $${vaeToUsd(draft.prize_pool)}\n💳 Total charged: $${vaeToUsd(total)}\n⏰ Duration: ${draft.duration_days} days\n\n<i>After deadline you have 72hrs to pick a winner.\nIf you don't pick, the top-rated entry wins automatically.</i>`,
    Markup.inlineKeyboard([
      [Markup.button.callback('👀 View Competition', `comp_view_${comp.id}`)],
      [Markup.button.callback('🔙 Menu', 'menu')],
    ])
  );
});

// ─── CONFIRM POST SOCIAL CONTEST ──────────────────────────────────────────────
bot.action('chal_confirm_post', async (ctx) => {
  await cb(ctx);
  const user = await db.getUser(ctx.from.id);
  const state = getState(ctx.from.id);
  const draft = state?.draft;
  if (!draft?.base_pay_per_post || !draft?.title) {
    return edit(ctx, '❌ No contest draft found.',
      Markup.inlineKeyboard([[Markup.button.callback('🔙 Back', 'competitions_menu')]]));
  }

  const deducted = await db.deductBalance(user.id, COMP.SETUP_FEE_SOCIAL);
  if (!deducted) {
    return edit(ctx, `❌ Insufficient balance. Setup fee: $${vaeToUsd(COMP.SETUP_FEE_SOCIAL)}.`,
      Markup.inlineKeyboard([[Markup.button.callback('💳 Add Funds', 'buy_vae')]]));
  }

  await db.recordTransaction(user.id, 'social_contest_setup', -COMP.SETUP_FEE_SOCIAL, null, `Posted contest: ${draft.title}`);

  const { data: chal } = await supabase.from('social_challenges').insert({
    requester_id: user.id,
    title: draft.title,
    description: draft.description,
    platform: draft.platform || 'Any',
    hashtag: draft.hashtag || null,
    base_pay_per_post: draft.base_pay_per_post,
    prize_structure: { '1st': draft.prize_1st, '2nd': draft.prize_2nd, '3rd': draft.prize_3rd },
    prize_pool: (draft.prize_1st || 0) + (draft.prize_2nd || 0) + (draft.prize_3rd || 0),
    setup_fee: COMP.SETUP_FEE_SOCIAL,
    platform_fee_pct: COMP.PLATFORM_FEE_PCT,
    setup_fee_paid: true,
    ai_content_allowed: true,
    requirements: draft.requirements || null,
    deadline: new Date(Date.now() + draft.duration_days * 86400000).toISOString(),
    status: 'active',
    entry_count: 0,
    approved_count: 0,
  }).select().single();

  clearState(ctx.from.id);

  return edit(ctx,
    `📱 <b>Social Contest Live!</b>\n\n"<b>${fmt.esc(draft.title)}</b>"\n💵 Base pay: $${vaeToUsd(draft.base_pay_per_post)}/post\n🥇$${vaeToUsd(draft.prize_1st)} | 🥈$${vaeToUsd(draft.prize_2nd)} | 🥉$${vaeToUsd(draft.prize_3rd)}\n💳 Setup fee charged: $${vaeToUsd(COMP.SETUP_FEE_SOCIAL)}\n⏰ Duration: ${draft.duration_days} days\n\n<i>Approve submissions as they come in — workers get paid instantly.\nBonus prizes awarded automatically 7 days after deadline based on engagement.</i>`,
    Markup.inlineKeyboard([
      [Markup.button.callback('👀 View Contest', `chal_view_${chal.id}`)],
      [Markup.button.callback('🔙 Menu', 'menu')],
    ])
  );
});

// ═══════════════════════════════════════════════════════════════════════════════
// TEXT HANDLER CASES — ADD THESE INSIDE the switch(state.action) block
// in the existing bot.on('text', ...) handler at line 4320
// Find the last case before the closing }); and add these cases before it
// ═══════════════════════════════════════════════════════════════════════════════

// Paste these cases into the switch block manually, or use the sed command below

const _compTextCases = {
  // ── comp_entry: worker submitting to open competition ──────────────────────
  comp_entry: async (ctx, state, user) => {
    const text = ctx.message.text;
    const { data: comp } = await supabase.from('competitions').select('title,prize_pool').eq('id', state.compId).single();

    await supabase.from('competition_entries').upsert({
      competition_id: state.compId,
      user_id: user.id,
      content: text,
      files: state.files || [],
      status: 'submitted',
      worker_wallet: user.crypto_address || null,
    }, { onConflict: 'competition_id,user_id' });

    // Increment entry count
    const { data: cur } = await supabase.from('competitions').select('entry_count').eq('id', state.compId).single();
    await supabase.from('competitions').update({ entry_count: (cur?.entry_count || 0) + 1 }).eq('id', state.compId);

    clearState(ctx.from.id);
    return send(ctx,
      `✅ <b>Entry Submitted!</b>\n\nCompetition: <b>${fmt.esc(comp?.title || '')}</b>\nPrize: $${vaeToUsd(comp?.prize_pool || 0)}\n\nGood luck! 🍀 The requester picks a winner after the deadline.\nYou'll be notified of the result.`,
      Markup.inlineKeyboard([
        [Markup.button.callback('🏆 Browse More', 'competitions_menu')],
        [Markup.button.callback('🔙 Menu', 'menu')],
      ])
    );
  },

  // ── chal_entry: worker submitting post URL to social contest ───────────────
  chal_entry: async (ctx, state, user) => {
    const url = ctx.message.text;
    const { data: chal } = await supabase.from('social_challenges').select('title,base_pay_per_post,platform').eq('id', state.chalId).single();

    const platform = url.includes('tiktok') ? 'TikTok'
      : url.includes('instagram') ? 'Instagram'
      : url.includes('youtube') || url.includes('youtu.be') ? 'YouTube'
      : url.includes('twitter') || url.includes('x.com') ? 'X/Twitter'
      : chal?.platform || 'Other';

    await supabase.from('challenge_entries').insert({
      challenge_id: state.chalId,
      user_id: user.id,
      post_url: url,
      post_link: url,
      platform,
      status: 'pending',
      worker_wallet: user.crypto_address || null,
    });

    const { data: cur } = await supabase.from('social_challenges').select('entry_count').eq('id', state.chalId).single();
    await supabase.from('social_challenges').update({ entry_count: (cur?.entry_count || 0) + 1 }).eq('id', state.chalId);

    clearState(ctx.from.id);
    return send(ctx,
      `📤 <b>Submitted for Review!</b>\n\nContest: <b>${fmt.esc(chal?.title || '')}</b>\nPlatform detected: ${platform}\n\nOnce approved you'll receive <b>$${vaeToUsd(chal?.base_pay_per_post || 0)}</b> instantly!\n🏆 Keep getting engagement for the bonus prizes!`,
      Markup.inlineKeyboard([
        [Markup.button.callback('📱 More Contests', 'competitions_menu')],
        [Markup.button.callback('🔙 Menu', 'menu')],
      ])
    );
  },

  // ── chal_reject_reason: requester sending rejection reason ─────────────────
  chal_reject_reason: async (ctx, state, user) => {
    const reason = ctx.message.text;
    await supabase.from('challenge_entries').update({ status: 'rejected' }).eq('id', state.entryId);
    const { data: entry } = await supabase.from('challenge_entries')
      .select('user_id,worker:app_users(telegram_id)').eq('id', state.entryId).single();
    const { data: chal } = await supabase.from('social_challenges').select('title').eq('id', state.chalId).single();
    if (entry?.worker?.telegram_id) {
      await _notifyComp(entry.worker.telegram_id,
        `❌ Your submission for "<b>${fmt.esc(chal?.title || '')}</b>" was not approved.\n\nReason: ${fmt.esc(reason)}\n\nPlease adjust and resubmit if the contest is still open.`
      );
    }
    clearState(ctx.from.id);
    return reviewChallengeSubmissions(ctx, state.chalId, supabase, edit, Markup, fmt, user.id);
  },

  // ── create_competition: multi-step creation flow ───────────────────────────
  create_competition: async (ctx, state, user) => {
    const draft = state.draft;
    const text = ctx.message.text.trim();

    if (!draft.title) {
      draft.title = text;
      setState(ctx.from.id, { ...state, draft });
      return send(ctx,
        `✅ Title: "<b>${fmt.esc(draft.title)}</b>"\n\n<b>Step 2 of 4: Describe your competition</b>\n<i>What should workers create or submit? Be specific about requirements.</i>`,
        Markup.inlineKeyboard([[Markup.button.callback('❌ Cancel', 'competitions_menu')]])
      );
    }

    if (!draft.description) {
      draft.description = text;
      setState(ctx.from.id, { ...state, draft });
      return send(ctx,
        `✅ Description set!\n\n<b>Step 3 of 4: Set your prize amount</b>\n• Minimum: $50\n• Workers keep 100% of prize\n<i>Just send the dollar amount, e.g. "200"</i>`,
        Markup.inlineKeyboard([[Markup.button.callback('❌ Cancel', 'competitions_menu')]])
      );
    }

    if (!draft.prize_pool) {
      const amt = Math.round(parseFloat(text.replace(/[^0-9.]/g, '')) * 100);
      if (!amt || amt < COMP.MIN_PRIZE_OPEN) {
        return send(ctx, `❌ Minimum prize is $${vaeToUsd(COMP.MIN_PRIZE_OPEN)}. Please enter a higher amount.`);
      }
      draft.prize_pool = amt;
      const fee = platformFee(amt);
      const total = totalCostOpen(amt);
      setState(ctx.from.id, { ...state, draft });
      return send(ctx,
        `✅ Prize: <b>$${vaeToUsd(amt)}</b>\n\n💰 <b>Cost breakdown:</b>\n• Prize: $${vaeToUsd(amt)}\n• Platform fee (25%): $${vaeToUsd(fee)}\n• Setup fee: $${vaeToUsd(COMP.SETUP_FEE_OPEN)}\n• <b>Total: $${vaeToUsd(total)}</b>\n• Winner receives: $${vaeToUsd(amt)} (100%)\n\n<b>Step 4 of 4: How many days should this run?</b>\n<i>Send a number (1–30)</i>`,
        Markup.inlineKeyboard([[Markup.button.callback('❌ Cancel', 'competitions_menu')]])
      );
    }

    if (!draft.duration_days) {
      const days = parseInt(text);
      if (!days || days < 1 || days > 30) {
        return send(ctx, '❌ Please enter a number between 1 and 30.');
      }
      draft.duration_days = days;
      setState(ctx.from.id, { ...state, draft });
      const total = totalCostOpen(draft.prize_pool);
      return send(ctx,
        `🏆 <b>Review Your Competition</b>\n\n📋 Title: ${fmt.esc(draft.title)}\n📝 ${fmt.esc(draft.description.substring(0, 100))}${draft.description.length > 100 ? '...' : ''}\n💰 Prize: $${vaeToUsd(draft.prize_pool)}\n⏰ Duration: ${days} days\n💳 <b>Total charged today: $${vaeToUsd(total)}</b>\n\n<i>Winner gets $${vaeToUsd(draft.prize_pool)} (100%). You pay $${vaeToUsd(total)}.</i>`,
        Markup.inlineKeyboard([
          [Markup.button.callback('✅ Post Competition', 'comp_confirm_post')],
          [Markup.button.callback('❌ Cancel', 'competitions_menu')],
        ])
      );
    }
  },

  // ── create_challenge: multi-step social contest creation ───────────────────
  create_challenge: async (ctx, state, user) => {
    const draft = state.draft;
    const text = ctx.message.text.trim();

    if (!draft.title) {
      draft.title = text;
      setState(ctx.from.id, { ...state, draft });
      return send(ctx,
        `✅ Title: "<b>${fmt.esc(draft.title)}</b>"\n\n<b>Step 2 of 5: Describe your challenge</b>\n<i>What should participants post? What message/vibe/format?</i>`,
        Markup.inlineKeyboard([[Markup.button.callback('❌ Cancel', 'competitions_menu')]])
      );
    }

    if (!draft.description) {
      draft.description = text;
      setState(ctx.from.id, { ...state, draft });
      return send(ctx,
        `✅ Description set!\n\n<b>Step 3 of 5: Set base pay per approved post</b>\n• Minimum: $3\n• Every approved post earns this instantly\n<i>Send the amount, e.g. "5"</i>`,
        Markup.inlineKeyboard([[Markup.button.callback('❌ Cancel', 'competitions_menu')]])
      );
    }

    if (!draft.base_pay_per_post) {
      const amt = Math.round(parseFloat(text.replace(/[^0-9.]/g, '')) * 100);
      if (!amt || amt < COMP.MIN_BASE_PAY) {
        return send(ctx, `❌ Minimum base pay is $${vaeToUsd(COMP.MIN_BASE_PAY)}.`);
      }
      draft.base_pay_per_post = amt;
      setState(ctx.from.id, { ...state, draft });
      return send(ctx,
        `✅ Base pay: <b>$${vaeToUsd(amt)}/post</b>\n\n<b>Step 4 of 5: Set bonus prizes</b>\nTop 3 by engagement get bonuses at contest end.\n\nSend 3 amounts separated by commas:\n<i>e.g. "50,25,10" → 1st=$50, 2nd=$25, 3rd=$10</i>`,
        Markup.inlineKeyboard([[Markup.button.callback('❌ Cancel', 'competitions_menu')]])
      );
    }

    if (!draft.prize_1st) {
      const parts = text.split(',').map(x => Math.round(parseFloat(x.trim()) * 100));
      if (parts.length < 3 || parts.some(isNaN) || parts.some(n => n < 0)) {
        return send(ctx, '❌ Please send 3 amounts separated by commas, e.g. "50,25,10"');
      }
      draft.prize_1st = parts[0];
      draft.prize_2nd = parts[1];
      draft.prize_3rd = parts[2];
      setState(ctx.from.id, { ...state, draft });
      return send(ctx,
        `✅ Bonuses set!\n🥇 1st: $${vaeToUsd(parts[0])}\n🥈 2nd: $${vaeToUsd(parts[1])}\n🥉 3rd: $${vaeToUsd(parts[2])}\n\n<b>Step 5 of 5: How many days should this run?</b>\n<i>Send a number (3–30)</i>`,
        Markup.inlineKeyboard([[Markup.button.callback('❌ Cancel', 'competitions_menu')]])
      );
    }

    if (!draft.duration_days) {
      const days = parseInt(text);
      if (!days || days < 3 || days > 30) {
        return send(ctx, '❌ Please enter a number between 3 and 30.');
      }
      draft.duration_days = days;
      setState(ctx.from.id, { ...state, draft });
      const bonusTotal = (draft.prize_1st || 0) + (draft.prize_2nd || 0) + (draft.prize_3rd || 0);
      const ex = 20; // example 20 posts
      const exCost = (draft.base_pay_per_post * ex) + platformFee(draft.base_pay_per_post * ex) + bonusTotal + platformFee(bonusTotal) + COMP.SETUP_FEE_SOCIAL;
      return send(ctx,
        `📱 <b>Review Your Contest</b>\n\n📋 ${fmt.esc(draft.title)}\n💵 Base pay: $${vaeToUsd(draft.base_pay_per_post)}/post\n🥇$${vaeToUsd(draft.prize_1st)} | 🥈$${vaeToUsd(draft.prize_2nd)} | 🥉$${vaeToUsd(draft.prize_3rd)}\n⏰ Duration: ${days} days\n💳 Setup fee now: $${vaeToUsd(COMP.SETUP_FEE_SOCIAL)}\n\n<i>Example cost for ${ex} approved posts: ~$${vaeToUsd(exCost)}</i>\n<i>Compare to agency charging $5,000+ for same campaign!</i>`,
        Markup.inlineKeyboard([
          [Markup.button.callback('🚀 Launch Contest', 'chal_confirm_post')],
          [Markup.button.callback('❌ Cancel', 'competitions_menu')],
        ])
      );
    }
  },
};

// ─── HOOK INTO EXISTING TEXT HANDLER ─────────────────────────────────────────
// The existing bot.on('text') at line 4320 has switch(state.action).
// We intercept competition/contest actions before the switch via middleware approach:
// Add this handler AFTER the existing bot.on('text') — it catches what the main handler misses.
// Since Telegraf processes handlers in order, use bot.on with a guard condition.

bot.on('text', async (ctx, next) => {
  const state = getState(ctx.from.id);
  const action = state?.action;
  if (!_compTextCases[action]) return next(); // pass to existing handler

  try {
    const user = await db.getUser(ctx.from.id);
    await _compTextCases[action](ctx, state, user);
  } catch (e) {
    console.error(`[Competition Text Handler] ${action}:`, e.message);
    await send(ctx, '❌ Something went wrong. Please try again.',
      Markup.inlineKeyboard([[Markup.button.callback('🔙 Menu', 'menu')]]));
  }
});

// ─── PHOTO/DOCUMENT HANDLER for competition entries ───────────────────────────
// Telegraf calls all matching handlers, so this runs alongside the existing one
bot.on(['photo', 'document'], async (ctx, next) => {
  const state = getState(ctx.from.id);
  if (state?.action !== 'comp_entry') return next();

  // Collect files into state
  const fileId = ctx.message?.photo?.slice(-1)[0]?.file_id || ctx.message?.document?.file_id;
  if (fileId) {
    const files = state.files || [];
    files.push(fileId);
    updateState(ctx.from.id, { files });
    await ctx.reply('📎 File received! Send more or send text to complete your submission.');
  }
});

// ═══════════════════════════════════════════════════════════════════════════════
// END OF COMPETITION BOT INTEGRATION
// ═══════════════════════════════════════════════════════════════════════════════
