#!/usr/bin/env tsx
/**
 * Mobile Viewport Smoke Test
 *
 * Quick regression test for mobile scaling issues.
 * Checks that the page fits the viewport correctly on key devices.
 *
 * Usage: npx tsx src/viewport-smoke.ts [--baseUrl=https://...]
 */

import { chromium, webkit, type Browser, type Page } from 'playwright';
import * as fs from 'fs';
import * as path from 'path';

interface DeviceConfig {
  name: string;
  width: number;
  height: number;
  engine: 'chromium' | 'webkit';
  deviceScaleFactor: number;
}

const DEVICES: DeviceConfig[] = [
  { name: 'iPhone-14-Pro', width: 390, height: 844, engine: 'webkit', deviceScaleFactor: 3 },
  { name: 'iPhone-15-Pro-Max', width: 430, height: 932, engine: 'webkit', deviceScaleFactor: 3 },
  { name: 'Android-360', width: 360, height: 800, engine: 'chromium', deviceScaleFactor: 3 },
  { name: 'Android-412', width: 412, height: 915, engine: 'chromium', deviceScaleFactor: 2.625 },
];

const ROUTES = ['/', '/forecasts', '/login', '/signup'];

interface TestResult {
  device: string;
  route: string;
  pass: boolean;
  issues: string[];
  screenshot: string;
}

async function runTests(baseUrl: string): Promise<TestResult[]> {
  const results: TestResult[] = [];
  const ssDir = path.resolve(import.meta.dirname || __dirname, '..', 'screenshots', 'viewport-smoke');
  fs.mkdirSync(ssDir, { recursive: true });

  // Group by engine
  const engineMap = new Map<string, DeviceConfig[]>();
  for (const d of DEVICES) {
    const list = engineMap.get(d.engine) || [];
    list.push(d);
    engineMap.set(d.engine, list);
  }

  for (const [engine, devices] of engineMap) {
    const browserType = engine === 'webkit' ? webkit : chromium;
    let browser: Browser;
    try {
      browser = await browserType.launch({ headless: true });
    } catch (err: any) {
      console.error(`  Failed to launch ${engine}: ${err.message}`);
      continue;
    }

    for (const device of devices) {
      const context = await browser.newContext({
        viewport: { width: device.width, height: device.height },
        deviceScaleFactor: device.deviceScaleFactor,
        isMobile: true,
        hasTouch: true,
      });

      for (const route of ROUTES) {
        const page = await context.newPage();
        const issues: string[] = [];
        const url = `${baseUrl}${route}`;
        const ssFile = `${device.name}_${route.replace(/\//g, '_') || 'home'}.png`;
        const ssPath = path.join(ssDir, ssFile);

        try {
          await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 20000 });
          // Wait for client-side hydration
          await page.waitForTimeout(5000);

          // Check 1: No horizontal overflow
          const overflowInfo = await page.evaluate(() => {
            const docWidth = document.documentElement.scrollWidth;
            const vpWidth = window.innerWidth;
            return { docWidth, vpWidth, overflows: docWidth > vpWidth + 2 };
          });

          if (overflowInfo.overflows) {
            issues.push(`Horizontal overflow: document ${overflowInfo.docWidth}px > viewport ${overflowInfo.vpWidth}px`);
          }

          // Check 2: Viewport meta tag present and correct
          const viewportMeta = await page.evaluate(() => {
            const tags = document.querySelectorAll('meta[name="viewport"]');
            return {
              count: tags.length,
              content: tags[0]?.getAttribute('content') || null,
            };
          });

          if (viewportMeta.count === 0) {
            issues.push('Missing viewport meta tag');
          } else if (viewportMeta.count > 1) {
            issues.push(`${viewportMeta.count} duplicate viewport meta tags found`);
          }

          if (viewportMeta.content && !viewportMeta.content.includes('width=device-width')) {
            issues.push(`Viewport meta missing width=device-width: "${viewportMeta.content}"`);
          }

          // Check 3: Key elements visible above the fold (skip nav check on auth pages)
          const isAuthPage = ['/login', '/signup'].includes(route);
          const aboveFold = await page.evaluate(({ checkNav }) => {
            const missing: string[] = [];

            if (checkNav) {
              const nav = document.querySelector('nav');
              if (!nav) missing.push('nav element missing');
              else {
                const rect = nav.getBoundingClientRect();
                if (rect.bottom <= 0) missing.push('nav not visible');
              }
            }

            // Main content should be present
            const main = document.querySelector('main');
            if (!main) {
              // Some pages use different root structure
              const body = document.body;
              if (!body.children.length) missing.push('page body is empty');
            }

            return missing;
          }, { checkNav: !isAuthPage });

          issues.push(...aboveFold);

          // Check 4: No body/html transform scaling
          const scaling = await page.evaluate(() => {
            const htmlStyle = window.getComputedStyle(document.documentElement);
            const bodyStyle = window.getComputedStyle(document.body);
            const problems: string[] = [];

            if (htmlStyle.transform !== 'none') problems.push(`html has transform: ${htmlStyle.transform}`);
            if (bodyStyle.transform !== 'none') problems.push(`body has transform: ${bodyStyle.transform}`);

            const htmlWidth = document.documentElement.getBoundingClientRect().width;
            const vpWidth = window.innerWidth;
            if (Math.abs(htmlWidth - vpWidth) > 2) {
              problems.push(`html width (${htmlWidth}px) != viewport width (${vpWidth}px)`);
            }

            return problems;
          });

          issues.push(...scaling);

          // Check 5: Input font-size >= 16px (iOS auto-zoom prevention) — only check on WebKit (iOS-like)
          if (device.engine === 'webkit') {
            const inputFontSize = await page.evaluate(() => {
              const inputs = document.querySelectorAll('input, select, textarea');
              const problems: string[] = [];
              inputs.forEach((input) => {
                const style = window.getComputedStyle(input);
                const fontSize = parseFloat(style.fontSize);
                if (fontSize < 16) {
                  const id = input.id || input.getAttribute('name') || input.tagName;
                  problems.push(`Input "${id}" has font-size ${fontSize}px (< 16px, triggers iOS zoom)`);
                }
              });
              return problems;
            });

            issues.push(...inputFontSize);
          }

          // Take screenshot
          await page.screenshot({ path: ssPath, fullPage: false });

        } catch (err: any) {
          issues.push(`Failed to load: ${err.message}`);
        }

        results.push({
          device: device.name,
          route,
          pass: issues.length === 0,
          issues,
          screenshot: ssPath,
        });

        await page.close();
      }

      await context.close();
    }

    await browser.close();
  }

  return results;
}

async function main() {
  const args = process.argv.slice(2);
  let baseUrl = 'https://rainmakersports.app';
  for (const arg of args) {
    if (arg.startsWith('--baseUrl=')) baseUrl = arg.split('=')[1];
  }

  console.log('='.repeat(50));
  console.log('  VIEWPORT SMOKE TEST');
  console.log('='.repeat(50));
  console.log(`  Target: ${baseUrl}`);
  console.log(`  Devices: ${DEVICES.map((d) => d.name).join(', ')}`);
  console.log(`  Routes: ${ROUTES.join(', ')}`);
  console.log('='.repeat(50));

  const results = await runTests(baseUrl);

  let passed = 0;
  let failed = 0;

  for (const r of results) {
    const icon = r.pass ? '\u2705' : '\u274C';
    console.log(`  ${icon} ${r.device} ${r.route}`);
    if (!r.pass) {
      for (const issue of r.issues) {
        console.log(`      - ${issue}`);
      }
      failed++;
    } else {
      passed++;
    }
  }

  console.log('='.repeat(50));
  console.log(`  PASSED: ${passed}  FAILED: ${failed}`);
  console.log('='.repeat(50));

  process.exit(failed > 0 ? 1 : 0);
}

main().catch((err) => {
  console.error('Fatal error:', err);
  process.exit(2);
});
