import axios from 'axios';
import * as cheerio from 'cheerio';

/**
 * Locale & Language Switcher Smoke Test
 *
 * For every URL in the sitemap:
 * 1. Fetches the page HTML
 * 2. Extracts <link rel="alternate" hreflang="..." href="..."> tags
 * 3. Verifies each alternate URL uses correctly translated slugs
 * 4. Verifies each alternate URL returns HTTP 200
 */

const targetUrl = process.argv[2] || process.env.NEXT_PUBLIC_BASE_URL || 'http://localhost:3000';
const gatekeeperPassword = process.env.GATEKEEPER_PASSWORD || 'klz2026';

// Expected slug translations: German key → English value
const SLUG_MAP: Record<string, string> = {
  produkte: 'products',
  kontakt: 'contact',
  niederspannungskabel: 'low-voltage-cables',
  mittelspannungskabel: 'medium-voltage-cables',
  hochspannungskabel: 'high-voltage-cables',
  solarkabel: 'solar-cables',
  impressum: 'legal-notice',
  datenschutz: 'privacy-policy',
  agbs: 'terms',
};

// Reverse map: English → German
const REVERSE_SLUG_MAP: Record<string, string> = Object.fromEntries(
  Object.entries(SLUG_MAP).map(([de, en]) => [en, de]),
);

const headers = { Cookie: `klz_gatekeeper_session=${gatekeeperPassword}` };

function getExpectedTranslation(
  sourcePath: string,
  sourceLocale: string,
  targetLocale: string,
  alternates: { hreflang: string; href: string }[],
): string | null {
  const segments = sourcePath.split('/').filter(Boolean);
  segments[0] = targetLocale;

  // Blog posts have dynamic slugs. If it's a blog post, trust the alternate tag
  // if the href is present in the sitemap.
  // The Smoke Test's primary job is ensuring the alternate links point to valid pages.
  if (segments[1] === (targetLocale === 'de' ? 'blog' : 'blog') && segments.length > 2) {
    const altLink = alternates.find((a) => a.hreflang === targetLocale);
    if (altLink) {
      return new URL(altLink.href).pathname;
    }
  }

  const map = sourceLocale === 'de' ? SLUG_MAP : REVERSE_SLUG_MAP;

  return (
    '/' +
    segments
      .map((seg, i) => {
        if (i === 0) return seg; // locale
        return map[seg] || seg; // translate or keep
      })
      .join('/')
  );
}

async function main() {
  console.log(`\n🌐 Starting Locale Smoke Test for: ${targetUrl}\n`);

  // 1. Fetch sitemap
  const sitemapUrl = `${targetUrl.replace(/\/$/, '')}/sitemap.xml`;
  console.log(`📥 Fetching sitemap from ${sitemapUrl}...`);
  const sitemapRes = await axios.get(sitemapUrl, { headers, validateStatus: (s) => s < 400 });
  const $sitemap = cheerio.load(sitemapRes.data, { xmlMode: true });

  let urls = $sitemap('url loc')
    .map((_i, el) => $sitemap(el).text())
    .get();

  const urlPattern = /https?:\/\/[^/]+/;
  urls = [...new Set(urls)]
    .filter((u) => u.startsWith('http'))
    .map((u) => u.replace(urlPattern, targetUrl.replace(/\/$/, '')))
    .sort();

  console.log(`✅ Found ${urls.length} URLs in sitemap.\n`);

  let totalChecked = 0;
  let totalPassed = 0;
  let totalFailed = 0;
  const failures: string[] = [];

  for (const url of urls) {
    const path = new URL(url).pathname;
    const locale = path.split('/')[1];
    if (!locale || !['de', 'en'].includes(locale)) continue;

    try {
      const res = await axios.get(url, { headers, validateStatus: null });
      if (res.status >= 400) continue; // Skip pages that are already broken (check-http catches those)

      const $ = cheerio.load(res.data);

      // Extract hreflang alternate links
      const alternates: { hreflang: string; href: string }[] = [];
      $('link[rel="alternate"][hreflang]').each((_i, el) => {
        const hreflang = $(el).attr('hreflang') || '';
        let href = $(el).attr('href') || '';
        if (href && hreflang && hreflang !== 'x-default') {
          href = href.replace(urlPattern, targetUrl.replace(/\/$/, ''));
          alternates.push({ hreflang, href });
        }
      });

      if (alternates.length === 0) {
        // Some pages may not have alternates, that's OK
        continue;
      }

      totalChecked++;

      // Validate each alternate
      let pageOk = true;

      for (const alt of alternates) {
        if (alt.hreflang === locale) continue; // Same locale, skip

        // 1. Check slug translation is correct
        const expectedPath = getExpectedTranslation(path, locale, alt.hreflang, alternates);
        const actualPath = new URL(alt.href).pathname;

        if (actualPath !== expectedPath) {
          console.error(
            `❌ SLUG MISMATCH: ${path} → hreflang="${alt.hreflang}" expected ${expectedPath} but got ${actualPath}`,
          );
          failures.push(
            `Slug mismatch: ${path} → ${alt.hreflang}: expected ${expectedPath}, got ${actualPath}`,
          );
          pageOk = false;
          continue;
        }

        // 2. Check alternate URL returns 200
        try {
          const altRes = await axios.get(alt.href, {
            headers,
            validateStatus: null,
            maxRedirects: 5,
          });
          if (altRes.status >= 400) {
            console.error(`❌ BROKEN ALTERNATE: ${path} → ${alt.href} returned ${altRes.status}`);
            failures.push(`Broken alternate: ${path} → ${alt.href} (${altRes.status})`);
            pageOk = false;
          }
        } catch (err: any) {
          console.error(`❌ NETWORK ERROR: ${path} → ${alt.href}: ${err.message}`);
          failures.push(`Network error: ${path} → ${alt.href}: ${err.message}`);
          pageOk = false;
        }
      }

      if (pageOk) {
        console.log(
          `✅ ${path} — alternates OK (${alternates
            .map((a) => a.hreflang)
            .filter((h) => h !== locale)
            .join(', ')})`,
        );
        totalPassed++;
      } else {
        totalFailed++;
      }
    } catch (err: any) {
      console.error(`❌ NETWORK ERROR fetching ${url}: ${err.message}`);
      totalFailed++;
    }
  }

  console.log(`\n${'─'.repeat(60)}`);
  console.log(`📊 Locale Smoke Test Results:`);
  console.log(`   Pages checked: ${totalChecked}`);
  console.log(`   Passed: ${totalPassed}`);
  console.log(`   Failed: ${totalFailed}`);

  if (failures.length > 0) {
    console.log(`\n❌ Failures:`);
    failures.forEach((f) => console.log(`   • ${f}`));
    console.log(`\n❌ Locale Smoke Test FAILED.`);
    process.exit(1);
  } else {
    console.log(`\n✨ All locale alternates are correctly translated and reachable!`);
    process.exit(0);
  }
}

main().catch((err) => {
  console.error(`\n❌ Critical error:`, err.message);
  process.exit(1);
});
