import fs from 'node:fs/promises';
import path from 'node:path';
import process from 'node:process';
import { chromium, devices } from 'playwright';

const baseUrl = process.env.BASE_URL ?? 'http://127.0.0.1:8000';
const adminSlug = process.env.ADMIN_SLUG ?? 'admin';
const outRoot = process.env.QA_OUT_DIR ?? path.resolve('storage/app/qa/manual-ui-audit');

const desktop = { name: 'desktop', viewport: { width: 1440, height: 900 } };
const mobile = { name: 'mobile', device: devices['Pixel 7'] };
const viewports = [desktop, mobile];

const routeGroups = {
  public: [
    { key: 'home', path: '/' },
    { key: 'about', path: '/about' },
    { key: 'products', path: '/products' },
    { key: 'awareness', path: '/awareness' },
    { key: 'bonus-income-plan', path: '/bonus-income-plan' },
    { key: 'club-rewards', path: '/club-rewards' },
    { key: 'gallery', path: '/gallery' },
    { key: 'legal', path: '/legal' },
    { key: 'franchise', path: '/franchise' },
    { key: 'contact', path: '/contact' },
    { key: 'login', path: '/login' },
  ],
  admin: [
    { key: 'dashboard', path: `/${adminSlug}/dashboard` },
    { key: 'members', path: `/${adminSlug}/members` },
    { key: 'tree', path: `/${adminSlug}/tree` },
    { key: 'plan', path: `/${adminSlug}/plan` },
    { key: 'products', path: `/${adminSlug}/products` },
    { key: 'orders', path: `/${adminSlug}/orders` },
    { key: 'payments', path: `/${adminSlug}/payments` },
    { key: 'income-engine', path: `/${adminSlug}/income-engine` },
    { key: 'wallet', path: `/${adminSlug}/wallet` },
    { key: 'withdrawals', path: `/${adminSlug}/withdrawals` },
    { key: 'reports', path: `/${adminSlug}/reports` },
    { key: 'ranks', path: `/${adminSlug}/ranks` },
    { key: 'kyc', path: `/${adminSlug}/kyc` },
    { key: 'franchises', path: `/${adminSlug}/franchises` },
    { key: 'cms-homepage', path: `/${adminSlug}/cms/homepage-settings` },
    { key: 'api', path: `/${adminSlug}/api` },
    { key: 'security', path: `/${adminSlug}/security` },
    { key: 'settings', path: `/${adminSlug}/settings` },
    { key: 'repair-tools', path: `/${adminSlug}/repair-tools` },
  ],
  user: [
    { key: 'dashboard', path: '/user/dashboard' },
    { key: 'profile', path: '/user/profile' },
    { key: 'team', path: '/user/team' },
    { key: 'tree', path: '/user/tree' },
    { key: 'wallet', path: '/user/wallet' },
    { key: 'withdrawals', path: '/user/withdrawals' },
    { key: 'shop', path: '/user/shop' },
    { key: 'orders', path: '/user/orders' },
    { key: 'referrals', path: '/user/referrals' },
    { key: 'plans', path: '/user/plans' },
    { key: 'income', path: '/user/income' },
    { key: 'rank', path: '/user/rank' },
    { key: 'support', path: '/user/support' },
    { key: 'announcements', path: '/user/announcements' },
  ],
  franchise: [
    { key: 'dashboard', path: '/franchise/dashboard' },
    { key: 'members', path: '/franchise/members' },
    { key: 'pos', path: '/franchise/pos' },
    { key: 'stock', path: '/franchise/stock' },
    { key: 'distribution', path: '/franchise/distribution' },
    { key: 'stock-requests', path: '/franchise/stock-requests' },
    { key: 'pickups', path: '/franchise/pickups' },
    { key: 'sales', path: '/franchise/sales' },
    { key: 'customers', path: '/franchise/customers' },
    { key: 'commission', path: '/franchise/commission' },
    { key: 'payments', path: '/franchise/payments' },
    { key: 'reports-daily', path: '/franchise/reports/daily' },
    { key: 'profit', path: '/franchise/profit-analytics' },
    { key: 'notifications', path: '/franchise/notifications' },
    { key: 'profile', path: '/franchise/profile' },
    { key: 'security', path: '/franchise/security' },
  ],
};

const logins = {
  admin: {
    loginPath: `/${adminSlug}`,
    dashboardPath: `/${adminSlug}/dashboard`,
    login: 'qa-admin@example.com',
    password: 'Password@123',
  },
  user: {
    loginPath: '/login-user',
    dashboardPath: '/user/dashboard',
    login: 'qa-user@example.com',
    password: 'Password@123',
  },
  franchise: {
    loginPath: '/login-franchise',
    dashboardPath: '/franchise/dashboard',
    login: 'qa-franchise@example.com',
    password: 'Password@123',
  },
};

await fs.mkdir(outRoot, { recursive: true });

const findings = [];

function cleanPathKey(input) {
  return input.replaceAll('/', '_').replaceAll(':', '_').replaceAll('?', '_');
}

async function auditPage(page, label, group, route) {
  const consoleErrors = [];
  const requestFailures = [];
  const pageErrors = [];

  const onConsole = (msg) => {
    if (msg.type() === 'error') {
      consoleErrors.push(msg.text());
    }
  };
  const onRequestFailed = (req) => {
    requestFailures.push(`${req.method()} ${req.url()} -> ${req.failure()?.errorText ?? 'failed'}`);
  };
  const onPageError = (err) => {
    pageErrors.push(String(err));
  };

  page.on('console', onConsole);
  page.on('requestfailed', onRequestFailed);
  page.on('pageerror', onPageError);

  const url = `${baseUrl}${route.path}`;
  const response = await page.goto(url, { waitUntil: 'networkidle', timeout: 45000 });
  await page.waitForTimeout(350);

  const status = response?.status() ?? 0;
  const hasOverflow = await page.evaluate(() => document.documentElement.scrollWidth - window.innerWidth > 2);
  const brokenImages = await page.evaluate(() =>
    Array.from(document.images)
      .filter((img) => img.complete && img.naturalWidth === 0)
      .map((img) => img.currentSrc || img.src || '(unknown)')
      .slice(0, 10)
  );
  const title = await page.title();

  const screenshotPath = path.join(outRoot, label, `${group}-${cleanPathKey(route.key)}.png`);
  await fs.mkdir(path.dirname(screenshotPath), { recursive: true });
  await page.screenshot({ path: screenshotPath, fullPage: true });

  if (status >= 400 || status === 0) {
    findings.push({
      severity: 'high',
      type: 'http_status',
      view: label,
      page: route.path,
      status,
      detail: `HTTP status ${status} on ${route.path}`,
    });
  }

  if (hasOverflow) {
    findings.push({
      severity: 'medium',
      type: 'responsive_overflow',
      view: label,
      page: route.path,
      status,
      detail: 'Horizontal overflow detected',
    });
  }

  for (const src of brokenImages) {
    findings.push({
      severity: 'medium',
      type: 'broken_image',
      view: label,
      page: route.path,
      status,
      detail: src,
    });
  }

  for (const text of consoleErrors.slice(0, 5)) {
    findings.push({
      severity: 'medium',
      type: 'console_error',
      view: label,
      page: route.path,
      status,
      detail: text,
    });
  }

  for (const text of requestFailures.slice(0, 5)) {
    findings.push({
      severity: 'medium',
      type: 'request_failed',
      view: label,
      page: route.path,
      status,
      detail: text,
    });
  }

  for (const text of pageErrors.slice(0, 5)) {
    findings.push({
      severity: 'high',
      type: 'page_error',
      view: label,
      page: route.path,
      status,
      detail: text,
    });
  }

  page.off('console', onConsole);
  page.off('requestfailed', onRequestFailed);
  page.off('pageerror', onPageError);

  return { route: route.path, status, title, overflow: hasOverflow, brokenImages: brokenImages.length, screenshotPath };
}

async function doLogin(page, role) {
  const loginData = logins[role];
  await page.goto(`${baseUrl}${loginData.loginPath}`, { waitUntil: 'networkidle', timeout: 45000 });
  await page.fill('input[name="login"]', loginData.login);
  await page.fill('input[name="password"]', loginData.password);
  await Promise.all([
    page.waitForNavigation({ waitUntil: 'networkidle', timeout: 45000 }),
    page.click('button[type="submit"]'),
  ]);
  const current = page.url();
  if (!current.includes(loginData.dashboardPath)) {
    throw new Error(`Login failed for ${role}. Expected dashboard path ${loginData.dashboardPath}, got ${current}`);
  }
}

const browser = await chromium.launch({ headless: true });

const summary = {
  generatedAt: new Date().toISOString(),
  baseUrl,
  outputDir: outRoot,
  checks: [],
  findings,
};

try {
  for (const viewport of viewports) {
    const context = viewport.device
      ? await browser.newContext({ ...viewport.device, baseURL: baseUrl })
      : await browser.newContext({ viewport: viewport.viewport, baseURL: baseUrl });

    const page = await context.newPage();
    const label = viewport.name;

    for (const route of routeGroups.public) {
      const res = await auditPage(page, label, 'public', route);
      summary.checks.push({ viewport: label, group: 'public', ...res });
    }

    await context.close();
  }

  for (const viewport of viewports) {
    for (const role of ['admin', 'user', 'franchise']) {
      const context = viewport.device
        ? await browser.newContext({ ...viewport.device, baseURL: baseUrl })
        : await browser.newContext({ viewport: viewport.viewport, baseURL: baseUrl });

      const page = await context.newPage();
      const label = `${viewport.name}-${role}`;

      await doLogin(page, role);
      const groupRoutes = routeGroups[role];
      for (const route of groupRoutes) {
        const res = await auditPage(page, label, role, route);
        summary.checks.push({ viewport: label, group: role, ...res });
      }

      await context.close();
    }
  }
} finally {
  await browser.close();
}

const summaryPath = path.join(outRoot, 'summary.json');
await fs.writeFile(summaryPath, JSON.stringify(summary, null, 2));
console.log(`QA summary: ${summaryPath}`);
console.log(`Total checks: ${summary.checks.length}`);
console.log(`Findings: ${summary.findings.length}`);
