const express = require('express');
const rateLimit = require('express-rate-limit');
const path = require('path');
const { validateUrl } = require('../lib/ssrf');

const router = express.Router();

const UA_STRINGS = {
  desktop: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
  mobile: 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1',
  googlebot: 'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)',
};

const redirectLimiter = rateLimit({
  keyGenerator: (req) => (req.session && req.session.user && req.session.user.id) ? 'user_' + req.session.user.id : req.ip, windowMs: 60_000, max: 20 });

router.post('/api/redirect-analyze', redirectLimiter, express.json(), async (req, res) => {
  const { url: rawUrl, userAgent = 'desktop', method = 'GET' } = req.body || {};

  const check = await validateUrl(rawUrl);
  if (!check.safe) return res.status(400).json({ error: check.error });

  const uaString = UA_STRINGS[userAgent] || UA_STRINGS.desktop;
  const MAX_STEPS = 15;
  const STEP_TIMEOUT = 10_000;

  const chain = [];
  const visitedUrls = new Set();
  let currentUrl = check.url;
  let loopDetected = false;
  const totalStart = Date.now();

  for (let step = 0; step < MAX_STEPS; step++) {
    if (visitedUrls.has(currentUrl)) { loopDetected = true; break; }
    visitedUrls.add(currentUrl);

    const controller = new AbortController();
    const timer = setTimeout(() => controller.abort(), STEP_TIMEOUT);
    const stepStart = Date.now();

    try {
      const response = await fetch(currentUrl, {
        method: method.toUpperCase(),
        redirect: 'manual',
        signal: controller.signal,
        headers: {
          'User-Agent': uaString,
          'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
          'Accept-Language': 'ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7',
        },
      });
      clearTimeout(timer);

      const stepTime = Date.now() - stepStart;
      const responseHeaders = {};
      response.headers.forEach((value, key) => { responseHeaders[key] = value; });
      const location = response.headers.get('location') || null;

      chain.push({ url: currentUrl, status: response.status, statusText: response.statusText, location, time: stepTime, headers: responseHeaders });

      if (response.status < 300 || response.status >= 400) break;
      if (!location) break;

      let nextUrl;
      try { nextUrl = new URL(location, currentUrl).href; } catch { break; }
      // Re-validate every hop before the next request (SSRF via redirect)
      const rcheck = await validateUrl(nextUrl);
      if (!rcheck.safe) {
        chain.push({ url: nextUrl, status: 0, statusText: 'Заблокировано: ' + rcheck.error, location: null, time: 0, headers: {} });
        break;
      }
      currentUrl = rcheck.url;
    } catch (err) {
      clearTimeout(timer);
      chain.push({ url: currentUrl, status: 0, statusText: err.name === 'AbortError' ? 'Timeout' : err.message, location: null, time: Date.now() - stepStart, headers: {} });
      break;
    }
  }

  const totalTime = Date.now() - totalStart;
  const finalUrl = chain.length > 0 ? chain[chain.length - 1].url : check.url;

  const issues = [];
  const redirectSteps = chain.filter(s => s.status >= 300 && s.status < 400);
  if (redirectSteps.length > 3) issues.push('long_chain');
  for (let i = 0; i < chain.length - 1; i++) {
    if (chain[i].url.startsWith('https://') && chain[i + 1].url.startsWith('http://')) { issues.push('mixed_protocol'); break; }
  }
  if (chain.some(s => s.status === 302)) issues.push('302_not_301');

  res.json({ chain, final_url: finalUrl, total_time: totalTime, loop_detected: loopDetected, issues });
});

// Page
router.get('/redirects', (req, res) => {
  res.sendFile(path.join(__dirname, '..', 'public', 'redirects.html'));
});

module.exports = router;
