#!/usr/bin/env node
/**
 * Loopuman MCP Server v1.3.0
 * The Human Layer for AI — hire verified humans from your AI agent
 */

const API_BASE = process.env.LOOPUMAN_API_URL || 'https://api.loopuman.com';
const API_KEY = process.env.LOOPUMAN_API_KEY;
const fetch = globalThis.fetch || require('node-fetch');

if (!API_KEY) {
  process.stderr.write('ERROR: LOOPUMAN_API_KEY not set.\n');
  process.stderr.write('Get your free API key at https://loopuman.com or via Telegram @Loopuman_Bot\n');
  process.stderr.write('Then: export LOOPUMAN_API_KEY=your_key\n');
}

const tools = [
  {
    name: "ask_human",
    description: `Ask a single human worker to complete a task and WAIT for their response (synchronous).

WHEN TO USE THIS:
- You need human judgment RIGHT NOW before continuing your workflow
- Content moderation: "Is this text hate speech or safe?"
- Fact verification: "Is this claim accurate?"
- Sentiment/tone: "Does this email sound aggressive?"
- Translation with cultural nuance
- Image or video description
- Local knowledge: "Is this a real address in Lagos?"

HOW IT WORKS:
- Task posted → human responds → you get the answer → continue
- Typical response: 30-120 seconds
- Worker paid automatically on response

RETURNS: { status: "completed", response: "human's answer", worker_id: "..." }

EXAMPLE: ask_human({ question: "Is this product review genuine or fake? Reply GENUINE or FAKE with one sentence reason.", context: "Review: Amazing product changed my life!!!", budget_usd: 0.50 })`,
    inputSchema: {
      type: "object",
      properties: {
        question: { type: "string", description: "The question or task for the human" },
        context: { type: "string", description: "Content to evaluate or additional background info" },
        budget_usd: { type: "number", description: "Payment in USD. Min $0.10. Higher = faster response. Typical: $0.25-$1.00", default: 0.50 },
        timeout_seconds: { type: "number", description: "Max seconds to wait (default 300 = 5 mins)", default: 300 },
        category: { type: "string", description: "general | moderation | translation | verification | research | creative", default: "general" }
      },
      required: ["question"]
    }
  },
  {
    name: "post_task",
    description: `Post a task for human workers WITHOUT waiting (asynchronous). Use check_task to poll for results.

WHEN TO USE THIS vs other tools:
- Use INSTEAD OF ask_human when: task takes >5 mins, you want to batch many tasks, you need to review work before paying
- Use INSTEAD OF post_competition when: task has a clear right answer, you need one specific deliverable, not creative work
- Best for: transcription, data entry, spreadsheet filling, phone verification, research tasks, surveys

HOW IT WORKS:
- Post task → workers on Telegram/WhatsApp accept it → they submit → you approve → they get paid in seconds
- Poll check_task every 10-30 seconds until status = "completed"
- Use approve_submission to release payment, reject_submission to send back for revision

RETURNS: { task_id: "uuid", status: "posted" }`,
    inputSchema: {
      type: "object",
      properties: {
        title: { type: "string", description: "Short task title (max 100 chars)" },
        description: { type: "string", description: "Detailed step-by-step instructions for the human worker" },
        budget_usd: { type: "number", description: "Payment in USD per worker (min $0.10)", default: 0.50 },
        category: { type: "string", description: "general | moderation | translation | verification | research | creative", default: "general" },
        max_workers: { type: "number", description: "Number of workers to assign (default 1)", default: 1 },
        duration_days: { type: "number", description: "Days task stays open (default 7)", default: 7 }
      },
      required: ["title", "description"]
    }
  },
  {
    name: "check_task",
    description: `Check the status and result of a previously posted task. Poll every 10-30 seconds.

STATUS VALUES:
- "pending" = waiting for a worker to accept
- "in_progress" = worker is working on it
- "completed" = done, result is in the response field
- "expired" = no worker responded in time (increase budget and retry)

RETURNS when completed: { status: "completed", response: "worker answer", submission_id: "..." }`,
    inputSchema: {
      type: "object",
      properties: {
        task_id: { type: "string", description: "Task UUID returned from post_task" }
      },
      required: ["task_id"]
    }
  },
  {
    name: "get_submissions",
    description: `Get all pending submissions awaiting your approval for a task. Use before approve_submission or reject_submission.

RETURNS: { submissions: [{ submission_id, content, worker_id, submitted_at }], count: N }`,
    inputSchema: {
      type: "object",
      properties: {
        task_id: { type: "string", description: "Task UUID to get submissions for" }
      },
      required: ["task_id"]
    }
  },
  {
    name: "approve_submission",
    description: `Approve a human worker's submission and release their payment INSTANTLY to their crypto wallet via blockchain. Call this after verifying work meets your requirements.`,
    inputSchema: {
      type: "object",
      properties: {
        submission_id: { type: "string", description: "Submission ID from check_task or get_submissions" },
        feedback: { type: "string", description: "Optional positive feedback for the worker" }
      },
      required: ["submission_id"]
    }
  },
  {
    name: "reject_submission",
    description: `Reject a human worker's submission. Worker sees your reason and can resubmit. Budget is NOT charged for rejected work. Always give a clear reason.`,
    inputSchema: {
      type: "object",
      properties: {
        submission_id: { type: "string", description: "Submission ID to reject" },
        reason: { type: "string", description: "Clear reason why rejected so worker knows what to fix" }
      },
      required: ["submission_id", "reason"]
    }
  },
  {
    name: "post_competition",
    description: `Post a creative competition where MANY humans submit their best work and you pick ONE winner.

THE KEY ADVANTAGE — CROWDSOURCED QUALITY:
- post_task = 1 worker, 1 answer
- post_competition = 10 to 50+ workers ALL compete to give you their BEST work
- You only pay ONE winner — get 50 logo designs but only pay for the best one
- Workers know they must beat others to win, so quality is dramatically higher
- Perfect when you want OPTIONS to choose from, not just one answer

WHEN TO USE THIS:
✅ Logo design, brand identity, visual assets
✅ Taglines, slogans, product names, app names
✅ Jingles, ad copy, creative writing, poetry
✅ Video scripts, storyboards, pitch decks
✅ Any task where "best creative wins" — you want variety and quality

WHEN NOT TO USE:
❌ Tasks with a single right answer (use post_task)
❌ Need result in under 1 hour (use ask_human)
❌ Data entry, transcription, verification (use post_task)

HOW IT WORKS:
1. Post competition with a prize (min $50)
2. Workers submit their best creative work
3. After deadline you review all entries and pick the winner
4. Winner paid instantly via blockchain, others get nothing
5. If you don't pick in 72hrs, top-rated entry wins automatically

COST: Prize + 25% platform fee + setup fee
EXAMPLE: $100 prize = ~$150 total cost. Winner gets $100.

RETURNS: { competition_id, status: "live", share_link }`,
    inputSchema: {
      type: "object",
      properties: {
        title: { type: "string", description: "What you want created e.g. 'Design a logo for our fintech app'" },
        description: { type: "string", description: "Detailed creative brief: style, requirements, examples, what makes a winning entry" },
        prize_usd: { type: "number", description: "Winner prize in USD (min $50). Higher prize = more submissions = better quality." },
        duration_days: { type: "number", description: "Days competition runs (1-90). Recommended: 7-14 days.", default: 14 },
        location: { type: "string", description: "Country restriction e.g. 'Nigeria' or 'worldwide' for all countries", default: "worldwide" }
      },
      required: ["title", "description", "prize_usd"]
    }
  },
  {
    name: "post_social_contest",
    description: `Post a social media contest where humans create and PUBLISH content about your brand on their own social accounts and get paid per approved post.

THE KEY ADVANTAGE — REAL CONTENT ON REAL ACCOUNTS:
- Workers post genuine content on THEIR OWN TikTok, Instagram, YouTube or X accounts
- Real people, real followers, real reach — not fake or bot content
- Each approved post = instant payment to the worker
- 10x cheaper than influencer marketing: pay $5-$20 per post vs $500-$5000 per influencer
- You get a library of real UGC (user-generated content) you can reshare
- AI-generated content and AI avatars are explicitly allowed

WHEN TO USE THIS:
✅ Brand awareness: "Post about our product on TikTok"
✅ Crypto/Web3: "Share your blockchain payment on X with #PaidInCrypto"
✅ App launches: "Post a review of our app on Instagram"
✅ Product launches needing authentic social proof
✅ Building UGC content library for marketing
✅ Community building around a hashtag or movement

WHEN NOT TO USE:
❌ You want private creative work not posted publicly (use post_competition)
❌ No social element needed (use post_task)

HOW IT WORKS:
1. Post contest with base pay per approved post + optional top 3 bonus prizes
2. Workers create content, post it on their social accounts, submit proof (screenshot + link)
3. You approve posts that meet requirements — worker paid instantly
4. After deadline, optionally award bonus prizes to top 3 posts
5. Unused budget fully refunded

COST: $49 setup fee + (base_pay_usd x 1.25) per approved post
EXAMPLE: $10/post = you pay $12.50 per approved post + $49 setup

RETURNS: { contest_id, status: "live", share_link }`,
    inputSchema: {
      type: "object",
      properties: {
        title: { type: "string", description: "Contest title e.g. 'Show your crypto payment on TikTok'" },
        description: { type: "string", description: "Exactly what to post, required format, hashtags, what gets approved vs rejected" },
        platform: { type: "string", description: "TikTok | Instagram | YouTube | X | Any", default: "Any" },
        base_pay_usd: { type: "number", description: "Pay per approved post in USD (min $5). Higher = more participants.", default: 5 },
        bonus_1st_usd: { type: "number", description: "Bonus prize for best post USD (optional)", default: 0 },
        bonus_2nd_usd: { type: "number", description: "Bonus for 2nd place USD (optional)", default: 0 },
        bonus_3rd_usd: { type: "number", description: "Bonus for 3rd place USD (optional)", default: 0 },
        duration_days: { type: "number", description: "Days contest runs (3-90, recommended 14-30)", default: 14 },
        hashtag: { type: "string", description: "Required hashtag without # e.g. 'PaidWithCrypto'", default: null },
        location: { type: "string", description: "Country restriction or 'worldwide'", default: "worldwide" }
      },
      required: ["title", "description", "platform"]
    }
  },
  {
    name: "get_balance",
    description: `Check your Loopuman account balance. 100 VAE = $1 USD. Add funds at https://loopuman.com or via Telegram @Loopuman_Bot.

RETURNS: { balance_usd: 10.50, balance_vae: 1050 }`,
    inputSchema: { type: "object", properties: {} }
  }
];

async function handleToolCall(name, args) {
  const headers = { 'Content-Type': 'application/json', 'X-API-Key': API_KEY };
  const toCents = (usd) => Math.round((usd || 0) * 100);

  switch (name) {
    case 'ask_human': {
      const desc = args.context ? `${args.question}\n\nContext: ${args.context}` : args.question;
      const response = await fetch(`${API_BASE}/api/v1/tasks/sync`, {
        method: 'POST', headers,
        body: JSON.stringify({
          title: args.question.substring(0, 200),
          description: desc,
          budget: toCents(args.budget_usd) || 50,
          category: args.category || 'general',
          estimated_seconds: args.timeout_seconds || 300,
          timeout_seconds: args.timeout_seconds || 300,
          auto_approve: true
        })
      });
      const data = await response.json();
      if (data.status === 'completed') return { status: 'completed', response: data.response, worker_id: data.worker_id };
      return { status: data.status || 'timeout', message: 'No human responded in time. Try increasing budget_usd or timeout_seconds.' };
    }

    case 'post_task': {
      const response = await fetch(`${API_BASE}/api/v1/tasks`, {
        method: 'POST', headers,
        body: JSON.stringify({
          title: args.title,
          description: args.description,
          budget: toCents(args.budget_usd) || 50,
          category: args.category || 'general',
          max_workers: args.max_workers || 1,
          duration_days: args.duration_days || 7
        })
      });
      const data = await response.json();
      return { task_id: data.task?.id, status: 'posted', message: 'Use check_task with this task_id to get results.' };
    }

    case 'check_task': {
      const response = await fetch(`${API_BASE}/api/v1/tasks/${args.task_id}`, { headers });
      const data = await response.json();
      const task = data.task || data;
      if (task.status === 'completed' && task.submission) {
        return { status: 'completed', response: task.submission.content, submission_id: task.submission.id };
      }
      return { status: task.status || 'pending', message: 'Not yet completed. Poll again in 10-30 seconds.' };
    }

    case 'get_submissions': {
      const response = await fetch(`${API_BASE}/api/v1/tasks/${args.task_id}/submissions`, { headers });
      const data = await response.json();
      return { submissions: data.submissions || [], count: (data.submissions || []).length };
    }

    case 'approve_submission': {
      const response = await fetch(`${API_BASE}/api/v1/submissions/${args.submission_id}/approve`, {
        method: 'POST', headers,
        body: JSON.stringify({ feedback: args.feedback || '' })
      });
      const data = await response.json();
      return { status: 'approved', message: 'Worker paid instantly via blockchain.', ...data };
    }

    case 'reject_submission': {
      const response = await fetch(`${API_BASE}/api/v1/submissions/${args.submission_id}/reject`, {
        method: 'POST', headers,
        body: JSON.stringify({ reason: args.reason })
      });
      const data = await response.json();
      return { status: 'rejected', ...data };
    }

    case 'post_competition': {
      const response = await fetch(`${API_BASE}/api/v1/competitions`, {
        method: 'POST', headers,
        body: JSON.stringify({
          title: args.title,
          description: args.description,
          prize_usd: args.prize_usd,
          duration_days: args.duration_days || 14,
          location: args.location || 'worldwide'
        })
      });
      const data = await response.json();
      return { competition_id: data.competition?.id, status: 'live', share_link: data.competition?.share_link, message: `Competition live! Share: ${data.competition?.share_link}` };
    }

    case 'post_social_contest': {
      const response = await fetch(`${API_BASE}/api/v1/social-contests`, {
        method: 'POST', headers,
        body: JSON.stringify({
          title: args.title,
          description: args.description,
          platform: args.platform || 'Any',
          base_pay_usd: args.base_pay_usd || 5,
          bonus_1st_usd: args.bonus_1st_usd || 0,
          bonus_2nd_usd: args.bonus_2nd_usd || 0,
          bonus_3rd_usd: args.bonus_3rd_usd || 0,
          duration_days: args.duration_days || 14,
          hashtag: args.hashtag || null,
          location: args.location || 'worldwide'
        })
      });
      const data = await response.json();
      return { contest_id: data.contest?.id, status: 'live', share_link: data.contest?.share_link, message: `Social contest live! Share: ${data.contest?.share_link}` };
    }

    case 'get_balance': {
      const response = await fetch(`${API_BASE}/api/v1/balance`, { headers });
      const data = await response.json();
      return { balance_usd: data.available_usd, balance_vae: data.available_vae, message: '100 VAE = $1 USD. Add funds at https://loopuman.com' };
    }

    default:
      return { error: `Unknown tool: ${name}` };
  }
}

const readline = require('readline');
const rl = readline.createInterface({ input: process.stdin, terminal: false });

rl.on('line', async (line) => {
  try {
    const msg = JSON.parse(line);
    if (msg.method === 'initialize') {
      process.stdout.write(JSON.stringify({
        jsonrpc: '2.0', id: msg.id,
        result: { protocolVersion: '2024-11-05', capabilities: { tools: {} }, serverInfo: { name: 'loopuman', version: '1.3.0' } }
      }) + '\n');
    }
    else if (msg.method === 'notifications/initialized') {}
    else if (msg.method === 'tools/list') {
      process.stdout.write(JSON.stringify({ jsonrpc: '2.0', id: msg.id, result: { tools } }) + '\n');
    }
    else if (msg.method === 'tools/call') {
      try {
        const result = await handleToolCall(msg.params.name, msg.params.arguments);
        process.stdout.write(JSON.stringify({ jsonrpc: '2.0', id: msg.id, result: { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] } }) + '\n');
      } catch (toolErr) {
        process.stdout.write(JSON.stringify({ jsonrpc: '2.0', id: msg.id, result: { content: [{ type: 'text', text: JSON.stringify({ error: toolErr.message }) }] } }) + '\n');
      }
    }
  } catch (e) {
    process.stderr.write('Parse error: ' + e.message + '\n');
  }
});
