/**
 * LOOPUMAN SEO SERVER
 * ═══════════════════════════════════════════════════════════════
 * Serves server-side rendered public task pages for Google indexing
 * 
 * Routes:
 *   GET /tasks              → paginated task listing
 *   GET /tasks/:slug        → individual task page
 *   GET /sitemap.xml        → dynamic XML sitemap
 *   GET /robots.txt         → robots file
 * 
 * Deploy: pm2 start seo-server.js --name seo-server
 * Port: 3003 (nginx proxies /tasks/* and /sitemap.xml here)
 * ═══════════════════════════════════════════════════════════════
 */

'use strict';
require('dotenv').config();

const express = require('express');
const { createClient } = require('@supabase/supabase-js');

const app  = express();
const PORT = process.env.SEO_PORT || 3003;

const supabase = createClient(
  process.env.SUPABASE_URL,
  process.env.SUPABASE_SERVICE_KEY
);

// ─── CONSTANTS ────────────────────────────────────────────────
const SITE_URL      = 'https://loopuman.com';
const TELEGRAM_BOT  = 'https://t.me/Loopuman_bot';
const WHATSAPP_LINK = 'https://wa.me/447700000000'; // update with real number
const VAE_PER_USD   = 100;
const TASKS_PER_PAGE = 20;

const CATEGORY_LABELS = {
  writing:     { label: 'Writing',        emoji: '✍️'  },
  data:        { label: 'Data & Research', emoji: '🔍' },
  translation: { label: 'Translation',    emoji: '🌐'  },
  audio:       { label: 'Audio',          emoji: '🎙️' },
  image:       { label: 'Image & Video',  emoji: '📸'  },
  local:       { label: 'Local Tasks',    emoji: '📍'  },
  ai_training: { label: 'AI Training',    emoji: '🤖'  },
  moderation:  { label: 'Moderation',     emoji: '🛡️' },
  other:       { label: 'Other',          emoji: '💼'  },
};

// ─── HELPERS ──────────────────────────────────────────────────

function slugify(title, id) {
  const slug = title
    .toLowerCase()
    .replace(/[^a-z0-9\s-]/g, '')
    .trim()
    .replace(/\s+/g, '-')
    .substring(0, 60);
  return `${slug}-${id.substring(0, 6)}`;
}

function idFromSlug(slug) {
  // UUID first segment is 8 chars, slug ends with first 6
  const parts = slug.split('-');
  const last = parts[parts.length - 1];
  // Try last part first, then last 6 chars of whole slug
  return last.length >= 6 ? last : slug.slice(-6);
}

function vaeToUsd(vae) {
  return (vae / VAE_PER_USD).toFixed(2);
}

function workerEarns(budget) {
  return vaeToUsd(budget * 0.8); // worker gets 80% (20% commission)
}

function getCategoryInfo(cat) {
  return CATEGORY_LABELS[cat] || CATEGORY_LABELS.other;
}

function timeAgo(dateStr) {
  const diff = Date.now() - new Date(dateStr).getTime();
  const mins  = Math.floor(diff / 60000);
  const hours = Math.floor(diff / 3600000);
  const days  = Math.floor(diff / 86400000);
  if (mins  < 60)  return `${mins}m ago`;
  if (hours < 24)  return `${hours}h ago`;
  return `${days}d ago`;
}

// ─── HTML TEMPLATES ───────────────────────────────────────────

const HEAD = (title, description, canonical, extra = '') => `<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>${title}</title>
  <meta name="description" content="${description}">
  <link rel="canonical" href="${canonical}">
  <meta property="og:title" content="${title}">
  <meta property="og:description" content="${description}">
  <meta property="og:url" content="${canonical}">
  <meta property="og:type" content="website">
  <meta property="og:image" content="${SITE_URL}/og-image.png">
  <meta name="twitter:card" content="summary_large_image">
  <meta name="twitter:title" content="${title}">
  <meta name="twitter:description" content="${description}">
  ${extra}
  <link rel="preconnect" href="https://fonts.googleapis.com">
  <link href="https://fonts.googleapis.com/css2?family=DM+Mono:wght@400;500&family=Fraunces:ital,opsz,wght@0,9..144,300;0,9..144,700;1,9..144,300&display=swap" rel="stylesheet">
  <style>
    *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

    :root {
      --teal:    #10B981;
      --teal-dk: #059669;
      --amber:   #F59E0B;
      --ink:     #0d1117;
      --ink2:    #1c2333;
      --muted:   #8b949e;
      --border:  #21262d;
      --card:    #161b22;
      --white:   #f0f6fc;
      --radius:  10px;
    }

    html { scroll-behavior: smooth; }

    body {
      font-family: 'DM Mono', monospace;
      background: var(--ink);
      color: var(--white);
      line-height: 1.6;
      min-height: 100vh;
    }

    a { color: var(--teal); text-decoration: none; }
    a:hover { text-decoration: underline; }

    /* ── NAV ── */
    nav {
      display: flex;
      align-items: center;
      justify-content: space-between;
      padding: 16px 32px;
      border-bottom: 1px solid var(--border);
      background: var(--ink);
      position: sticky;
      top: 0;
      z-index: 100;
    }
    .nav-logo {
      font-family: 'Fraunces', serif;
      font-size: 1.4rem;
      font-weight: 700;
      color: var(--white);
    }
    .nav-logo span { color: var(--teal); }
    .nav-links { display: flex; gap: 24px; font-size: 0.8rem; }
    .nav-links a { color: var(--muted); }
    .nav-links a:hover { color: var(--white); text-decoration: none; }
    .nav-cta {
      background: var(--teal);
      color: var(--ink) !important;
      padding: 8px 18px;
      border-radius: var(--radius);
      font-weight: 500;
    }
    .nav-cta:hover { background: var(--teal-dk); text-decoration: none !important; }

    /* ── HERO STRIP ── */
    .hero-strip {
      background: linear-gradient(135deg, var(--ink2) 0%, #0d2818 100%);
      border-bottom: 1px solid var(--border);
      padding: 48px 32px 36px;
      text-align: center;
    }
    .hero-strip h1 {
      font-family: 'Fraunces', serif;
      font-size: clamp(1.8rem, 4vw, 2.8rem);
      font-weight: 700;
      color: var(--white);
      margin-bottom: 12px;
    }
    .hero-strip h1 em {
      font-style: italic;
      color: var(--teal);
    }
    .hero-strip p {
      color: var(--muted);
      font-size: 0.9rem;
      max-width: 540px;
      margin: 0 auto 24px;
    }
    .hero-badges {
      display: flex;
      gap: 12px;
      justify-content: center;
      flex-wrap: wrap;
    }
    .badge {
      display: inline-flex;
      align-items: center;
      gap: 6px;
      background: var(--card);
      border: 1px solid var(--border);
      border-radius: 20px;
      padding: 6px 14px;
      font-size: 0.75rem;
      color: var(--muted);
    }
    .badge .dot {
      width: 6px; height: 6px;
      border-radius: 50%;
      background: var(--teal);
    }

    /* ── FILTERS ── */
    .filters-bar {
      display: flex;
      gap: 10px;
      padding: 20px 32px;
      overflow-x: auto;
      border-bottom: 1px solid var(--border);
      background: var(--ink2);
    }
    .filter-pill {
      white-space: nowrap;
      padding: 6px 16px;
      border-radius: 20px;
      border: 1px solid var(--border);
      font-size: 0.75rem;
      color: var(--muted);
      cursor: pointer;
      transition: all 0.15s;
    }
    .filter-pill:hover, .filter-pill.active {
      border-color: var(--teal);
      color: var(--teal);
      background: rgba(16,185,129,0.08);
      text-decoration: none;
    }

    /* ── MAIN LAYOUT ── */
    .container {
      max-width: 1100px;
      margin: 0 auto;
      padding: 32px 24px;
    }

    /* ── TASK GRID ── */
    .task-grid {
      display: grid;
      grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
      gap: 16px;
    }

    .task-card {
      background: var(--card);
      border: 1px solid var(--border);
      border-radius: var(--radius);
      padding: 20px;
      transition: border-color 0.15s, transform 0.15s;
      position: relative;
      overflow: hidden;
    }
    .task-card::before {
      content: '';
      position: absolute;
      top: 0; left: 0; right: 0;
      height: 2px;
      background: var(--teal);
      transform: scaleX(0);
      transition: transform 0.2s;
      transform-origin: left;
    }
    .task-card:hover {
      border-color: var(--teal);
      transform: translateY(-2px);
    }
    .task-card:hover::before { transform: scaleX(1); }

    .task-card-header {
      display: flex;
      align-items: flex-start;
      justify-content: space-between;
      margin-bottom: 10px;
      gap: 12px;
    }
    .task-cat-badge {
      font-size: 0.7rem;
      padding: 3px 10px;
      border-radius: 12px;
      background: rgba(16,185,129,0.1);
      color: var(--teal);
      border: 1px solid rgba(16,185,129,0.25);
      white-space: nowrap;
    }
    .task-time { font-size: 0.7rem; color: var(--muted); white-space: nowrap; }

    .task-card h3 {
      font-family: 'Fraunces', serif;
      font-size: 1rem;
      font-weight: 600;
      color: var(--white);
      margin-bottom: 8px;
      line-height: 1.4;
    }
    .task-card h3 a { color: inherit; }
    .task-card h3 a:hover { color: var(--teal); text-decoration: none; }

    .task-desc {
      font-size: 0.78rem;
      color: var(--muted);
      margin-bottom: 16px;
      display: -webkit-box;
      -webkit-line-clamp: 2;
      -webkit-box-orient: vertical;
      overflow: hidden;
    }

    .task-card-footer {
      display: flex;
      align-items: center;
      justify-content: space-between;
    }
    .task-earn {
      display: flex;
      flex-direction: column;
    }
    .task-earn .amount {
      font-size: 1.1rem;
      font-weight: 500;
      color: var(--teal);
    }
    .task-earn .label { font-size: 0.68rem; color: var(--muted); }

    .task-cta {
      background: var(--teal);
      color: var(--ink);
      padding: 8px 16px;
      border-radius: 8px;
      font-size: 0.75rem;
      font-weight: 500;
      transition: background 0.15s;
    }
    .task-cta:hover { background: var(--teal-dk); text-decoration: none; }

    /* ── PAGINATION ── */
    .pagination {
      display: flex;
      gap: 8px;
      justify-content: center;
      margin-top: 40px;
    }
    .page-btn {
      padding: 8px 16px;
      border-radius: 8px;
      border: 1px solid var(--border);
      color: var(--muted);
      font-size: 0.8rem;
      background: var(--card);
      transition: all 0.15s;
    }
    .page-btn:hover, .page-btn.active {
      border-color: var(--teal);
      color: var(--teal);
      text-decoration: none;
    }
    .page-btn.active { background: rgba(16,185,129,0.1); }

    /* ── TASK DETAIL PAGE ── */
    .task-detail {
      max-width: 780px;
      margin: 0 auto;
      padding: 40px 24px;
    }
    .breadcrumb {
      font-size: 0.75rem;
      color: var(--muted);
      margin-bottom: 24px;
    }
    .breadcrumb a { color: var(--muted); }
    .breadcrumb span { margin: 0 6px; }

    .detail-header {
      margin-bottom: 32px;
    }
    .detail-header .cat-line {
      display: flex;
      align-items: center;
      gap: 10px;
      margin-bottom: 12px;
      font-size: 0.8rem;
      color: var(--teal);
    }
    .detail-header h1 {
      font-family: 'Fraunces', serif;
      font-size: clamp(1.5rem, 3vw, 2.2rem);
      font-weight: 700;
      line-height: 1.3;
      margin-bottom: 12px;
    }
    .detail-meta {
      display: flex;
      gap: 16px;
      flex-wrap: wrap;
      font-size: 0.75rem;
      color: var(--muted);
    }

    .detail-body {
      background: var(--card);
      border: 1px solid var(--border);
      border-radius: var(--radius);
      padding: 28px;
      margin-bottom: 24px;
      font-size: 0.85rem;
      color: var(--white);
      line-height: 1.8;
      white-space: pre-wrap;
    }

    .detail-pay-card {
      background: linear-gradient(135deg, #0d2818, var(--card));
      border: 1px solid rgba(16,185,129,0.3);
      border-radius: var(--radius);
      padding: 28px;
      margin-bottom: 24px;
    }
    .detail-pay-card h2 {
      font-family: 'Fraunces', serif;
      font-size: 1rem;
      color: var(--muted);
      font-weight: 300;
      margin-bottom: 6px;
    }
    .detail-pay-card .big-earn {
      font-size: 2.4rem;
      font-weight: 500;
      color: var(--teal);
      margin-bottom: 4px;
    }
    .detail-pay-card .sub {
      font-size: 0.75rem;
      color: var(--muted);
      margin-bottom: 20px;
    }
    .detail-pay-card .breakdown {
      display: flex;
      gap: 20px;
      flex-wrap: wrap;
      margin-bottom: 24px;
      padding: 16px;
      background: rgba(0,0,0,0.2);
      border-radius: 8px;
      font-size: 0.75rem;
    }
    .breakdown-item { color: var(--muted); }
    .breakdown-item strong { color: var(--white); display: block; font-size: 0.85rem; }

    .cta-buttons {
      display: flex;
      gap: 12px;
      flex-wrap: wrap;
    }
    .btn-primary {
      display: inline-flex;
      align-items: center;
      gap: 8px;
      background: var(--teal);
      color: var(--ink);
      padding: 12px 24px;
      border-radius: var(--radius);
      font-size: 0.85rem;
      font-weight: 500;
      transition: background 0.15s;
    }
    .btn-primary:hover { background: var(--teal-dk); text-decoration: none; }
    .btn-secondary {
      display: inline-flex;
      align-items: center;
      gap: 8px;
      background: var(--card);
      color: var(--white);
      padding: 12px 24px;
      border-radius: var(--radius);
      border: 1px solid var(--border);
      font-size: 0.85rem;
      font-weight: 500;
      transition: border-color 0.15s;
    }
    .btn-secondary:hover { border-color: var(--teal); text-decoration: none; }

    .how-it-works {
      background: var(--card);
      border: 1px solid var(--border);
      border-radius: var(--radius);
      padding: 28px;
      margin-bottom: 24px;
    }
    .how-it-works h3 {
      font-family: 'Fraunces', serif;
      font-size: 1rem;
      margin-bottom: 16px;
      color: var(--white);
    }
    .steps {
      display: flex;
      flex-direction: column;
      gap: 12px;
    }
    .step {
      display: flex;
      align-items: flex-start;
      gap: 14px;
      font-size: 0.8rem;
    }
    .step-num {
      width: 24px; height: 24px;
      border-radius: 50%;
      background: rgba(16,185,129,0.15);
      border: 1px solid rgba(16,185,129,0.3);
      color: var(--teal);
      display: flex; align-items: center; justify-content: center;
      font-size: 0.7rem;
      flex-shrink: 0;
    }
    .step-text { color: var(--muted); padding-top: 2px; }
    .step-text strong { color: var(--white); }

    .similar-tasks h3 {
      font-family: 'Fraunces', serif;
      font-size: 1.1rem;
      margin-bottom: 16px;
    }

    /* ── EMPTY STATE ── */
    .empty {
      text-align: center;
      padding: 80px 24px;
      color: var(--muted);
    }
    .empty h2 { font-family: 'Fraunces', serif; margin-bottom: 8px; color: var(--white); }

    /* ── FOOTER ── */
    footer {
      border-top: 1px solid var(--border);
      padding: 32px;
      text-align: center;
      font-size: 0.75rem;
      color: var(--muted);
      margin-top: 60px;
    }
    footer a { color: var(--muted); }
    footer a:hover { color: var(--teal); }
    .footer-links { display: flex; gap: 20px; justify-content: center; margin-bottom: 12px; }

    /* ── RESPONSIVE ── */
    @media (max-width: 640px) {
      nav { padding: 14px 16px; }
      .nav-links { display: none; }
      .hero-strip { padding: 32px 16px 24px; }
      .filters-bar { padding: 14px 16px; }
      .container { padding: 24px 16px; }
      .task-grid { grid-template-columns: 1fr; }
    }
  </style>
</head>
<body>`;

const NAV = () => `
<nav>
  <a href="${SITE_URL}" class="nav-logo">Loop<span>uman</span></a>
  <div class="nav-links">
    <a href="/tasks">Browse Tasks</a>
    <a href="${SITE_URL}/#how-it-works">How It Works</a>
    <a href="${SITE_URL}/#pricing">Pricing</a>
    <a href="${TELEGRAM_BOT}" class="nav-cta">Start Earning →</a>
  </div>
</nav>`;

const FOOTER = () => `
<footer>
  <div class="footer-links">
    <a href="${SITE_URL}">Home</a>
    <a href="/tasks">All Tasks</a>
    <a href="${SITE_URL}/privacy">Privacy</a>
    <a href="${SITE_URL}/terms">Terms</a>
    <a href="${TELEGRAM_BOT}">Telegram Bot</a>
  </div>
  <div>© ${new Date().getFullYear()} Loopuman · The Human Layer for AI · Paid in 8 Seconds</div>
</footer>
</body></html>`;

// ─── ROUTES ───────────────────────────────────────────────────

// TASK LISTING PAGE
app.get('/tasks', async (req, res) => {
  try {
    const page     = Math.max(1, parseInt(req.query.page) || 1);
    const category = req.query.cat || null;
    const offset   = (page - 1) * TASKS_PER_PAGE;

    let query = supabase
      .from('tasks')
      .select('id, title, category, budget, max_workers, status, created_at, description', { count: 'exact' })
      .in('status', ['open', 'active']).neq('status', 'full')
      .order('created_at', { ascending: false })
      .range(offset, offset + TASKS_PER_PAGE - 1);

    if (category) query = query.eq('category', category);

    const { data: tasks, error, count } = await query;
    if (error) throw error;

    const totalPages = Math.ceil((count || 0) / TASKS_PER_PAGE);
    const canonical  = `${SITE_URL}/tasks${category ? `?cat=${category}` : ''}${page > 1 ? `?page=${page}` : ''}`;

    const metaTitle = category
      ? `${getCategoryInfo(category).label} Tasks Online – Earn Crypto Instantly | Loopuman`
      : `Browse Micro Tasks – Earn Money Online, Paid in 8 Seconds | Loopuman`;

    const metaDesc = `Find ${count || 'hundreds of'} paid micro tasks on Loopuman. Complete tasks via Telegram or WhatsApp, earn crypto in 8 seconds. No bank account needed. Available worldwide.`;

    // Filter pills
    const filterPills = Object.entries(CATEGORY_LABELS).map(([key, val]) =>
      `<a href="/tasks?cat=${key}" class="filter-pill ${category === key ? 'active' : ''}">${val.emoji} ${val.label}</a>`
    ).join('');

    // Task cards
    const cards = (tasks || []).map(t => {
      const slug    = slugify(t.title, t.id);
      const catInfo = getCategoryInfo(t.category);
      const earn    = workerEarns(t.budget);
      const desc    = (t.description || '').substring(0, 120);
      return `
      <article class="task-card" itemscope itemtype="https://schema.org/JobPosting">
        <meta itemprop="title" content="${t.title.replace(/"/g, '&quot;')}">
        <meta itemprop="datePosted" content="${t.created_at}">
        <meta itemprop="employmentType" content="CONTRACTOR">
        <meta itemprop="hiringOrganization" content="Loopuman">
        <meta itemprop="jobLocation" content="Worldwide">
        <div itemprop="jobLocation" itemscope itemtype="https://schema.org/Place"><meta itemprop="name" content="Worldwide"></div>
        <meta itemprop="jobLocationType" content="TELECOMMUTE">
        <div class="task-card-header">
          <span class="task-cat-badge">${catInfo.emoji} ${catInfo.label}</span>
          <span class="task-time">${timeAgo(t.created_at)}</span>
        </div>
        <h3 itemprop="title"><a href="/tasks/${slug}">${t.title}</a></h3>
        ${desc ? `<p class="task-desc" itemprop="description">${desc}…</p>` : ''}
        <div class="task-card-footer">
          <div class="task-earn">
            <span itemprop="baseSalary" itemscope itemtype="https://schema.org/MonetaryAmount"><meta itemprop="currency" content="USD"><span itemprop="value">$${earn}</span></span>
            <span class="label">you earn · ${t.max_workers || 1} spot${(t.max_workers || 1) > 1 ? 's' : ''}</span>
          </div>
          <a href="/tasks/${slug}" class="task-cta">View Task →</a>
        </div>
      </article>`;
    }).join('');

    // Pagination
    const pageLinks = Array.from({ length: Math.min(totalPages, 10) }, (_, i) => i + 1).map(p =>
      `<a href="/tasks?${category ? `cat=${category}&` : ''}page=${p}" class="page-btn ${p === page ? 'active' : ''}">${p}</a>`
    ).join('');

    const html = `${HEAD(metaTitle, metaDesc, canonical)}
${NAV()}
<div class="hero-strip">
  <h1>Find tasks. Earn <em>instantly</em>.</h1>
  <p>Complete micro tasks via Telegram or WhatsApp. Get paid in 8 seconds in crypto. No bank account needed.</p>
  <div class="hero-badges">
    <span class="badge"><span class="dot"></span>${count || 0} open tasks</span>
    <span class="badge"><span class="dot"></span>Paid in 8 seconds</span>
    <span class="badge"><span class="dot"></span>Available worldwide</span>
    <span class="badge"><span class="dot"></span>No app needed</span>
  </div>
</div>
<div class="filters-bar">
  <a href="/tasks" class="filter-pill ${!category ? 'active' : ''}">🌐 All Tasks</a>
  ${filterPills}
</div>
<div class="container">
  ${tasks && tasks.length > 0
    ? `<div class="task-grid">${cards}</div>
       ${totalPages > 1 ? `<div class="pagination">${pageLinks}</div>` : ''}`
    : `<div class="empty">
         <h2>No tasks right now</h2>
         <p>Check back soon — new tasks are posted every few minutes.</p>
       </div>`
  }
</div>
${FOOTER()}`;

    res.setHeader('Content-Type', 'text/html');
    res.setHeader('Cache-Control', 'public, max-age=120'); // 2 min cache
    res.send(html);

  } catch (err) {
    console.error('[SEO] /tasks error:', err.message);
    res.status(500).send('Server error');
  }
});

// INDIVIDUAL TASK PAGE
app.get('/tasks/:slug', async (req, res) => {
  try {
    const slug   = req.params.slug;
    const prefix = idFromSlug(slug);

    // Find task by ID prefix
    const { data: allTasks, error } = await supabase
      .from('tasks')
      .select('id, title, category, budget, max_workers, status, created_at, description, expires_at')
      .order('created_at', { ascending: false })
      .limit(500);
    const tasks = allTasks ? allTasks.filter(t => t.id.replace(/-/g,'').startsWith(prefix) || t.id.startsWith(prefix)) : [];

    if (error) throw error;
    const task = tasks[0];

    if (!task) {
      return res.status(404).send(`${HEAD('Task Not Found | Loopuman', 'This task no longer exists.', `${SITE_URL}/tasks/${slug}`)}
${NAV()}
<div class="empty" style="padding:120px 24px">
  <h2>Task not found</h2>
  <p>This task may have expired or been removed.</p>
  <a href="/tasks" style="display:inline-block;margin-top:20px;color:var(--teal)">← Browse all tasks</a>
</div>
${FOOTER()}`);
    }

    const catInfo   = getCategoryInfo(task.category);
    const earn      = workerEarns(task.budget);
    const earnVAE   = Math.floor(task.budget * 0.8);
    const canonical = `${SITE_URL}/tasks/${slugify(task.title, task.id)}`;
    const isOpen    = task.status === 'open';

    const metaTitle = `${task.title} – Earn $${earn} Online | Loopuman`;
    const metaDesc  = `${task.title}. Earn $${earn} USD completing this ${catInfo.label.toLowerCase()} task via Telegram. Paid in 8 seconds. No experience required.`;

    // JSON-LD JobPosting schema — this is what Google shows as rich results
    const jsonLd = JSON.stringify({
      "@context": "https://schema.org",
      "@type": "JobPosting",
      "title": task.title,
      "description": task.description || task.title,
      "datePosted": task.created_at,
      "validThrough": task.expires_at || new Date(Date.now() + 7 * 86400000).toISOString(),
      "employmentType": "CONTRACTOR",
      "hiringOrganization": {
        "@type": "Organization",
        "name": "Loopuman",
        "sameAs": SITE_URL,
        "logo": `${SITE_URL}/logo.png`
      },
      "jobLocation": {
        "@type": "Place",
        "address": { "@type": "PostalAddress", "addressCountry": "WORLDWIDE" }
      },
      "applicantLocationRequirements": {
        "@type": "Country",
        "name": "Worldwide"
      },
      "jobLocationType": "TELECOMMUTE",
      "baseSalary": {
        "@type": "MonetaryAmount",
        "currency": "USD",
        "value": {
          "@type": "QuantitativeValue",
          "value": parseFloat(earn),
          "unitText": "TASK"
        }
      },
      "skills": catInfo.label,
      "industry": "Freelance / Micro-tasks",
      "url": canonical
    });

    // Fetch similar tasks
    const { data: similar } = await supabase
      .from('tasks')
      .select('id, title, category, budget, created_at')
      .in('status', ['open', 'active']).neq('status', 'full')
      .eq('category', task.category)
      .neq('id', task.id)
      .limit(3);

    const similarCards = (similar || []).map(t => {
      const s = slugify(t.title, t.id);
      return `
      <article class="task-card">
        <div class="task-card-header">
          <span class="task-cat-badge">${getCategoryInfo(t.category).emoji} ${getCategoryInfo(t.category).label}</span>
          <span class="task-time">${timeAgo(t.created_at)}</span>
        </div>
        <h3><a href="/tasks/${s}">${t.title}</a></h3>
        <div class="task-card-footer">
          <div class="task-earn">
            <span class="amount">$${workerEarns(t.budget)}</span>
            <span class="label">you earn</span>
          </div>
          <a href="/tasks/${s}" class="task-cta">View →</a>
        </div>
      </article>`;
    }).join('');

    const html = `${HEAD(metaTitle, metaDesc, canonical, `<script type="application/ld+json">${jsonLd}</script>`)}
${NAV()}
<div class="task-detail">
  <div class="breadcrumb">
    <a href="${SITE_URL}">Home</a>
    <span>›</span>
    <a href="/tasks">Tasks</a>
    <span>›</span>
    <a href="/tasks?cat=${task.category}">${catInfo.label}</a>
    <span>›</span>
    ${task.title}
  </div>

  <div class="detail-header">
    <div class="cat-line">
      <span>${catInfo.emoji}</span>
      <span>${catInfo.label}</span>
      <span>·</span>
      <span style="color:${isOpen ? 'var(--teal)' : 'var(--amber)'}">● ${isOpen ? 'Open' : 'Closed'}</span>
    </div>
    <h1>${task.title}</h1>
    <div class="detail-meta">
      <span>Posted ${timeAgo(task.created_at)}</span>
      <span>·</span>
      <span>${task.max_workers || 1} worker slot${(task.max_workers || 1) > 1 ? 's' : ''}</span>
      ${task.expires_at ? `<span>·</span><span>Expires ${new Date(task.expires_at).toLocaleDateString()}</span>` : ''}
    </div>
  </div>

  ${task.description ? `<div class="detail-body">${task.description}</div>` : ''}

  <div class="detail-pay-card">
    <h2>Your earnings</h2>
    <div class="big-earn">$${earn}</div>
    <div class="sub">${earnVAE} VAE · paid in 8 seconds via Celo blockchain</div>
    <div class="breakdown">
      <div class="breakdown-item"><strong>$${vaeToUsd(task.budget)}</strong>Task budget</div>
      <div class="breakdown-item"><strong>−20%</strong>Platform fee</div>
      <div class="breakdown-item"><strong>$${earn}</strong>You receive</div>
      <div class="breakdown-item"><strong>8 sec</strong>Payment speed</div>
    </div>
    ${isOpen ? `
    <div class="cta-buttons">
      <a href="${TELEGRAM_BOT}" class="btn-primary">
        <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M12 0C5.373 0 0 5.373 0 12s5.373 12 12 12 12-5.373 12-12S18.627 0 12 0zm5.894 8.221l-1.97 9.28c-.145.658-.537.818-1.084.508l-3-2.21-1.447 1.394c-.16.16-.295.295-.605.295l.213-3.053 5.56-5.023c.242-.213-.054-.333-.373-.12L7.17 13.401l-2.965-.924c-.643-.204-.657-.643.136-.953l11.57-4.461c.537-.194 1.006.131.983.158z"/></svg>
        Complete on Telegram
      </a>
      <a href="${WHATSAPP_LINK}" class="btn-secondary">
        <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413z"/></svg>
        Complete on WhatsApp
      </a>
    </div>` : `<p style="color:var(--amber);font-size:0.85rem">⏸ This task is currently closed. <a href="/tasks">Browse open tasks →</a></p>`}
  </div>

  <div class="how-it-works">
    <h3>How it works</h3>
    <div class="steps">
      <div class="step"><div class="step-num">1</div><div class="step-text"><strong>Open Telegram</strong> — Search @Loopuman_bot or click the button above</div></div>
      <div class="step"><div class="step-num">2</div><div class="step-text"><strong>Find this task</strong> — Type /tasks or browse categories</div></div>
      <div class="step"><div class="step-num">3</div><div class="step-text"><strong>Submit your work</strong> — Follow the instructions and submit directly in chat</div></div>
      <div class="step"><div class="step-num">4</div><div class="step-text"><strong>Get paid in 8 seconds</strong> — Crypto lands in your wallet instantly on approval</div></div>
    </div>
  </div>

  ${similar && similar.length > 0 ? `
  <div class="similar-tasks">
    <h3>Similar ${catInfo.label} tasks</h3>
    <div class="task-grid">${similarCards}</div>
  </div>` : ''}
</div>
${FOOTER()}`;

    res.setHeader('Content-Type', 'text/html');
    res.setHeader('Cache-Control', 'public, max-age=300'); // 5 min cache
    res.send(html);

  } catch (err) {
    console.error('[SEO] /tasks/:slug error:', err.message);
    res.status(500).send('Server error');
  }
});

app.get('/sitemap.xml', async (req, res) => {
  try {
    // Fetch tasks
    const { data: tasks } = await supabase
      .from('tasks')
      .select('id, title, created_at, status')
      .in('status', ['open', 'active']).neq('status', 'full')
      .order('created_at', { ascending: false })
      .limit(1000);

    // Fetch blog posts ← NEW
    const { data: posts } = await supabase
      .from('blog_posts')
      .select('slug, updated_at')
      .eq('published', true)
      .order('published_at', { ascending: false });

    const taskUrls = (tasks || []).map(t => `
  <url>
    <loc>${SITE_URL}/tasks/${slugify(t.title, t.id)}</loc>
    <lastmod>${t.created_at.split('T')[0]}</lastmod>
    <changefreq>weekly</changefreq>
    <priority>0.8</priority>
  </url>`).join('');

    const categoryUrls = Object.keys(CATEGORY_LABELS).map(cat => `
  <url>
    <loc>${SITE_URL}/tasks?cat=${cat}</loc>
    <changefreq>daily</changefreq>
    <priority>0.7</priority>
  </url>`).join('');

    // Blog URLs ← NEW
    const blogUrls = (posts || []).map(p => `
  <url>
    <loc>${SITE_URL}/blog/${p.slug}</loc>
    <lastmod>${p.updated_at.split('T')[0]}</lastmod>
    <changefreq>monthly</changefreq>
    <priority>0.8</priority>
  </url>`).join('');

    const xml = `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <url>
    <loc>${SITE_URL}/</loc>
    <changefreq>daily</changefreq>
    <priority>1.0</priority>
  </url>
  <url>
    <loc>${SITE_URL}/blog</loc>
    <changefreq>daily</changefreq>
    <priority>0.9</priority>
  </url>
  <url>
    <loc>${SITE_URL}/tasks</loc>
    <changefreq>hourly</changefreq>
    <priority>0.9</priority>
  </url>
  ${categoryUrls}
  ${blogUrls}
  ${taskUrls}
</urlset>`;

    res.setHeader('Content-Type', 'application/xml');
    res.setHeader('Cache-Control', 'public, max-age=3600');
    res.send(xml);
  } catch (err) {
    console.error('[SEO] /sitemap.xml error:', err.message);
    res.status(500).send('Error generating sitemap');
  }
});

// ROBOTS.TXT
app.get('/robots.txt', (req, res) => {
  res.setHeader('Content-Type', 'text/plain');
  res.send(`User-agent: *
Allow: /
Sitemap: ${SITE_URL}/sitemap.xml`);
});

// ─── START ────────────────────────────────────────────────────
app.listen(PORT, () => {
  console.log(`🔍 SEO Server running on port ${PORT}`);
  console.log(`   Tasks listing: http://localhost:${PORT}/tasks`);
  console.log(`   Sitemap:       http://localhost:${PORT}/sitemap.xml`);
});
