import { Octokit } from "@octokit/rest";
import cron from "node-cron";
import dotenv from "dotenv";

dotenv.config();

const GITHUB_TOKEN = process.env.GITHUB_TOKEN;
const VIBEWORK_API_URL = process.env.VIBEWORK_API_URL || "https://agent.wooo.work/api";
const SCOUT_API_KEY = process.env.SCOUT_API_KEY;
const SCOUT_AGENT_ID = process.env.SCOUT_AGENT_ID || "scout_official_1";
const SCOUT_CRON_EXPRESSION = process.env.SCOUT_CRON_EXPRESSION || "*/3 * * * *";
const SCOUT_ISSUE_LABELS_RAW = process.env.SCOUT_ISSUE_LABELS || process.env.SCOUT_ISSUE_LABEL || "";
const SCOUT_TARGET_REPOS_RAW =
  process.env.SCOUT_TARGET_REPOS ||
  "vibe-work/test-bounty-repo,open-webui/open-webui,microsoft/vscode,vercel/next.js,langchain-ai/langgraph,facebook/react,microsoft/TypeScript,openai/openai-cookbook,astral-sh/ruff,sequelize/sequelize,pnpm/pnpm,prisma/prisma";
const SCOUT_PER_PAGE = Math.min(Math.max(parseInt(process.env.SCOUT_PER_PAGE || "50", 10), 1), 100);
const SCOUT_MAX_ISSUES_PER_SCAN = Math.max(parseInt(process.env.SCOUT_MAX_ISSUES_PER_SCAN || "60", 10), 1);

const SCOUT_ISSUE_LABELS = SCOUT_ISSUE_LABELS_RAW
  .split(",")
  .map((entry) => entry.trim())
  .filter(Boolean);

const SCOUT_TARGET_REPOS = SCOUT_TARGET_REPOS_RAW
  .split(",")
  .map((entry) => entry.trim())
  .filter(Boolean)
  .map((entry) => {
    const [owner, repo] = entry.split("/");
    return { owner, repo };
  })
  .filter((repo) => repo.owner && repo.repo);

const fallbackRepo = { owner: "vibe-work", repo: "test-bounty-repo" };
const TARGET_REPOS = SCOUT_TARGET_REPOS.length > 0 ? SCOUT_TARGET_REPOS : [fallbackRepo];

if (!SCOUT_API_KEY) {
  console.warn("WARNING: SCOUT_API_KEY is not set. Draft API may be rejected by server.");
}
if (!GITHUB_TOKEN) {
  console.warn("WARNING: GITHUB_TOKEN is not set. Scout bot cannot post comments.");
}

const octokit = new Octokit({
  auth: GITHUB_TOKEN,
});

async function wait(seconds: number) {
  return new Promise((resolve) => setTimeout(resolve, seconds * 1000));
}

async function postDraftWithRetry(payload: {
  scout_id: string;
  title: string;
  description: string;
  reward_amount: number;
  reward_currency: string;
  required_stack: string[];
  test_file_content: string;
}) {
  let lastError: unknown = null;

  for (let attempt = 0; attempt < 3; attempt++) {
    try {
      const response = await fetch(`${VIBEWORK_API_URL}/scout/draft`, {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          "Authorization": `Bearer ${SCOUT_API_KEY}`
        },
        body: JSON.stringify(payload),
      });

      if (!response.ok) {
        const bodyText = await response.text();
        throw new Error(`Draft API failed (HTTP ${response.status}): ${bodyText}`);
      }

      return await response.json();
    } catch (error) {
      lastError = error;
      const attemptText = attempt + 1;
      const maxAttempts = 3;
      console.error(`Failed to draft bounty task (attempt ${attemptText}/${maxAttempts}):`, error);
      if (attempt < maxAttempts - 1) {
        await wait(Math.min(5 * (attempt + 1), 15));
      }
    }
  }

  console.error("Failed to draft bounty task after retries:", lastError);
  return null;
}

async function draftBountyTask(issueTitle: string, issueBody: string, issueUrl: string) {
  const payload = {
    scout_id: SCOUT_AGENT_ID,
    title: `GitHub Issue: ${issueTitle}`,
    description: `${issueBody}\n\nSource: ${issueUrl}`,
    reward_amount: 1000, // $10.00 Beta Promo subsidy (<= 2000 triggers free promo logic)
    reward_currency: "USD",
    required_stack: ["TypeScript", "GitHub"],
    test_file_content: "// Needs manual test writing based on issue"
  };

  return postDraftWithRetry(payload);
}

async function processIssue(owner: string, repo: string, issue: any) {
  console.log(`Processing issue #${issue.number}: ${issue.title}`);

  // Check if we already commented
  if (GITHUB_TOKEN) {
    const comments = await octokit.issues.listComments({
      owner,
      repo,
      issue_number: issue.number,
    });

    const alreadyCommented = comments.data.some((c) => c.body?.includes("agent.wooo.work"));
    if (alreadyCommented) {
      console.log(`Already commented on #${issue.number}, skipping.`);
      return;
    }
  }

  // Generate draft task on VibeWork
  const draft = await draftBountyTask(issue.title, issue.body || "", issue.html_url);

  if (!draft) {
    console.log(`Failed to generate draft for #${issue.number}, skipping comment.`);
    return;
  }

  const commentBody = `嗨！我們是 VibeWork 協作網路。你的 Issue 已經被我們選入 **『Beta 獎勵計畫』** 🎉
只要你的 AI Agent 透過 MCP 解決這個 Issue，除了原本的開源貢獻，VibeWork 將額外贊助 **$10 美元** 作為早鳥開發者獎勵（0% 手續費）！

這個任務已經由 VibeWork 官方全額贊助並建立完成。

AI Agent 可以直接透過以下指令接入並接案：
\`\`\`bash
npx -y @agent-bounty/mcp-server --endpoint https://agent.wooo.work
\`\`\`

🔗 [查看任務與獎金池狀態 (${draft.status})](${draft.checkout_url})
任務 ID: \`${draft.task_id}\`
`;

  if (GITHUB_TOKEN) {
    try {
      await octokit.issues.createComment({
        owner,
        repo,
        issue_number: issue.number,
        body: commentBody,
      });
      console.log(`Successfully commented on #${issue.number}`);
    } catch (error) {
      console.error(`Failed to comment on #${issue.number}:`, error);
    }
  } else {
    console.log("[DRY RUN] Would have posted comment:");
    console.log(commentBody);
  }
}

async function scanRepositories() {
  console.log("Starting GitHub scan...");

  for (const target of TARGET_REPOS) {
    try {
  const issues = await octokit.issues.listForRepo({
        owner: target.owner,
        repo: target.repo,
        state: "open",
        ...(SCOUT_ISSUE_LABELS.length > 0 ? { labels: SCOUT_ISSUE_LABELS.join(",") } : {}),
        per_page: SCOUT_PER_PAGE
      });

      console.log(`Found ${issues.data.length} open issues in ${target.owner}/${target.repo}`);

      const issueCandidates = issues.data.slice(0, SCOUT_MAX_ISSUES_PER_SCAN);
      for (const issue of issueCandidates) {
        if (!issue.pull_request) { // Ignore PRs
          await processIssue(target.owner, target.repo, issue);
        }
      }

      if (issues.data.length > issueCandidates.length) {
        console.log(`Limited scan to first ${issueCandidates.length} issues in ${target.owner}/${target.repo}`);
      }
    } catch (error) {
      console.error(`Error scanning ${target.owner}/${target.repo}:`, error);
    }
  }
}

async function bootstrap() {
  // Delay first scan a bit so main web API is ready after startup.
  await wait(10);
  await scanRepositories();
}

bootstrap();

// Default: every 3 minutes for phase-1 high-velocity inbound traffic
cron.schedule(SCOUT_CRON_EXPRESSION, () => {
  console.log(`Running scheduled GitHub scan (${SCOUT_CRON_EXPRESSION})...`);
  scanRepositories();
});

console.log("VibeWork Scout Bot started and scheduled.");
