const readline = require('readline');
const { connect } = require('puppeteer-real-browser');
const { spawn } = require('child_process');
const path = require('path');

const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout
});

const colors = {
  reset: "\x1b[0m",
  bright: "\x1b[1m",
  cyan: "\x1b[36m",
  green: "\x1b[32m",
  yellow: "\x1b[33m",
  red: "\x1b[31m",
  magenta: "\x1b[35m",
  gray: "\x1b[90m"
};

function clearConsole() {
  process.stdout.write('\x1Bc');
}

function printHeader() {
  clearConsole();
  console.log(`${colors.cyan}${colors.bright}====================================================`);
  console.log("             ANTI-CLOUDFLARE SCRAPER BOT             ");
  console.log(`====================================================${colors.reset}`);
  console.log(`${colors.gray}Powered by puppeteer-real-browser & cf-clearance-scraper${colors.reset}\n`);
}

function askQuestion(query) {
  return new Promise((resolve) => rl.question(query, resolve));
}

async function handleWafSession() {
  printHeader();
  console.log(`${colors.yellow}[Mode: Get WAF Session (Cookies & Headers)]${colors.reset}\n`);
  const url = await askQuestion(`${colors.bright}Enter target URL (e.g. https://nopecha.com/demo/cloudflare): ${colors.reset}`);
  if (!url) return;

  console.log(`\n${colors.cyan}Launching browser...${colors.reset}`);
  const { browser, page } = await connect({
    headless: false,
    turnstile: true,
    connectOption: { defaultViewport: null }
  });

  try {
    console.log(`${colors.cyan}Navigating to target site...${colors.reset}`);
    await page.goto(url, { waitUntil: 'domcontentloaded' });
    console.log(`${colors.yellow}Wait for WAF check to pass (approx. 10-15 seconds)...${colors.reset}`);
    
    // Give turnstile solver and security system a moment to clear
    await new Promise(r => setTimeout(r, 12000));

    const cookies = await page.cookies();
    const userAgent = await page.evaluate(() => navigator.userAgent);

    console.log(`\n${colors.green}${colors.bright}[SUCCESS] Cloudflare Bypassed Successfully!${colors.reset}`);
    console.log(`\n${colors.bright}User-Agent:${colors.reset} ${userAgent}`);
    console.log(`\n${colors.bright}Cookies:${colors.reset}`);
    console.log(JSON.stringify(cookies, null, 2));

    const cfClearance = cookies.find(c => c.name === 'cf_clearance');
    if (cfClearance) {
      console.log(`\n${colors.green}${colors.bright}[FOUND] 'cf_clearance' cookie: ${cfClearance.value}${colors.reset}`);
    } else {
      console.log(`\n${colors.yellow}[INFO] No 'cf_clearance' cookie found. WAF might already be satisfied.${colors.reset}`);
    }

  } catch (err) {
    console.error(`\n${colors.red}[ERROR] ${err.message}${colors.reset}`);
  } finally {
    await browser.close();
    await askQuestion(`\nPress Enter to return to main menu...`);
  }
}

async function handleScrapeHtml() {
  printHeader();
  console.log(`${colors.yellow}[Mode: Scrape Page HTML Source]${colors.reset}\n`);
  const url = await askQuestion(`${colors.bright}Enter target URL to scrape: ${colors.reset}`);
  if (!url) return;

  console.log(`\n${colors.cyan}Launching browser...${colors.reset}`);
  const { browser, page } = await connect({
    headless: false,
    turnstile: true,
    connectOption: { defaultViewport: null }
  });

  try {
    console.log(`${colors.cyan}Navigating and scraping...${colors.reset}`);
    
    let html = null;
    page.on('response', async (res) => {
      if ([200, 302].includes(res.status()) && [url, url + '/'].includes(res.url())) {
        await page.waitForNavigation({ waitUntil: 'load', timeout: 5000 }).catch(() => {});
        html = await page.content();
      }
    });

    await page.goto(url, { waitUntil: 'domcontentloaded' });
    
    // Safety delay to ensure response was processed and captured
    await new Promise(r => setTimeout(r, 8000));

    if (html) {
      console.log(`\n${colors.green}${colors.bright}[SUCCESS] Scraped ${html.length} bytes of HTML.${colors.reset}`);
      const preview = html.substring(0, 1000) + "\n... (truncated)";
      console.log(`\n${colors.bright}Preview of HTML:${colors.reset}\n${preview}`);
    } else {
      console.log(`\n${colors.red}[FAILED] Could not scrape HTML from page.${colors.reset}`);
    }

  } catch (err) {
    console.error(`\n${colors.red}[ERROR] ${err.message}${colors.reset}`);
  } finally {
    await browser.close();
    await askQuestion(`\nPress Enter to return to main menu...`);
  }
}

async function handleSolveTurnstile() {
  printHeader();
  console.log(`${colors.yellow}[Mode: Solve Turnstile & Extract Token]${colors.reset}\n`);
  const url = await askQuestion(`${colors.bright}Enter Turnstile Challenge URL: ${colors.reset}`);
  if (!url) return;

  console.log(`\n${colors.cyan}Launching browser...${colors.reset}`);
  const { browser, page } = await connect({
    headless: false,
    turnstile: true,
    connectOption: { defaultViewport: null }
  });

  try {
    await page.evaluateOnNewDocument(() => {
      let token = null;
      async function waitForToken() {
        while (!token) {
          try {
            token = window.turnstile.getResponse();
          } catch (e) {}
          await new Promise((resolve) => setTimeout(resolve, 500));
        }
        const c = document.createElement("input");
        c.type = "hidden";
        c.name = "cf-response";
        c.value = token;
        document.body.appendChild(c);
      }
      waitForToken();
    });

    console.log(`${colors.cyan}Navigating to page...${colors.reset}`);
    await page.goto(url, { waitUntil: 'domcontentloaded' });

    console.log(`${colors.yellow}Waiting for Turnstile verification box to be clicked...${colors.reset}`);
    await page.waitForSelector('[name="cf-response"]', { timeout: 45000 });

    const token = await page.evaluate(() => {
      const input = document.querySelector('[name="cf-response"]');
      return input ? input.value : null;
    });

    console.log(`\n${colors.green}${colors.bright}[SUCCESS] Turnstile Solved!${colors.reset}`);
    console.log(`\n${colors.bright}Token:${colors.reset}\n${token}`);

  } catch (err) {
    console.error(`\n${colors.red}[ERROR] ${err.message}${colors.reset}`);
  } finally {
    await browser.close();
    await askQuestion(`\nPress Enter to return to main menu...`);
  }
}

function handleStartApiServer() {
  printHeader();
  console.log(`${colors.green}[Mode: Start API Server]${colors.reset}\n`);
  console.log(`${colors.cyan}Starting server.js in background...${colors.reset}`);
  
  const serverPath = path.join(__dirname, 'server.js');
  const serverProcess = spawn('node', [serverPath], {
    stdio: 'inherit',
    shell: true
  });

  serverProcess.on('error', (err) => {
    console.error(`\n${colors.red}[ERROR] Failed to start API server: ${err.message}${colors.reset}`);
  });

  console.log(`\n${colors.green}${colors.bright}[RUNNING] Server has been started on port 3000!${colors.reset}`);
  console.log(`${colors.yellow}Close this terminal windows or press Ctrl+C to terminate it.${colors.reset}\n`);
  rl.close();
}

async function mainMenu() {
  while (true) {
    printHeader();
    console.log(`${colors.bright}Choose an action:${colors.reset}`);
    console.log(`  ${colors.cyan}1)${colors.reset} Get WAF Session (Cookies & User-Agent)`);
    console.log(`  ${colors.cyan}2)${colors.reset} Scrape Page HTML Source`);
    console.log(`  ${colors.cyan}3)${colors.reset} Solve Turnstile (Extract Token)`);
    console.log(`  ${colors.cyan}4)${colors.reset} Start API Server (Background Service)`);
    console.log(`  ${colors.cyan}5)${colors.reset} Exit\n`);

    const choice = await askQuestion(`${colors.bright}Enter choice (1-5): ${colors.reset}`);
    
    if (choice === '1') {
      await handleWafSession();
    } else if (choice === '2') {
      await handleScrapeHtml();
    } else if (choice === '3') {
      await handleSolveTurnstile();
    } else if (choice === '4') {
      handleStartApiServer();
      break;
    } else if (choice === '5') {
      console.log(`\n${colors.magenta}Goodbye!${colors.reset}`);
      rl.close();
      break;
    }
  }
}

mainMenu();
