/**
 * Route Generator
 *
 * Scans src/pages/ directory and generates a route manifest.
 * Run this at build time to create _routes.ts
 *
 * File naming conventions:
 * - [slug].tsx → Dynamic segment (matches any value)
 * - index.tsx → Directory root
 * - name.tsx → Static segment
 *
 * Example:
 *   src/pages/sap/bc/adt/cts/transportrequests/[slug].tsx
 *   → Pattern: /sap/bc/adt/cts/transportrequests/:slug
 */

import { readdirSync, statSync, writeFileSync } from 'node:fs';
import { join, relative, dirname } from 'node:path';

interface RouteInfo {
  pattern: string;
  regex: string;
  importPath: string;
  isDynamic: boolean;
}

const PAGES_DIR = join(dirname(import.meta.dirname), 'src/pages');
const OUTPUT_FILE = join(dirname(import.meta.dirname), 'src/pages/_routes.ts');

function scanDirectory(dir: string, routes: RouteInfo[] = []): RouteInfo[] {
  const entries = readdirSync(dir);

  for (const entry of entries) {
    const fullPath = join(dir, entry);
    const stat = statSync(fullPath);

    if (stat.isDirectory()) {
      // Recurse into subdirectories
      scanDirectory(fullPath, routes);
    } else if (entry.endsWith('.tsx') && !entry.startsWith('_')) {
      // Process page files (skip _routes.ts, _layout.tsx, etc.)
      const relativePath = relative(PAGES_DIR, fullPath);
      const route = pathToRoute(relativePath);
      if (route) {
        routes.push(route);
      }
    }
  }

  return routes;
}

function pathToRoute(filePath: string): RouteInfo | null {
  // Skip generic pages (GenericPage.tsx, index.ts exports)
  if (filePath === 'GenericPage.tsx' || filePath === 'index.ts') {
    return null;
  }

  // Remove .tsx extension
  let routePath = filePath.replace(/\.tsx$/, '');

  // Handle index files
  if (routePath.endsWith('/index')) {
    routePath = routePath.slice(0, -6); // Remove '/index'
  }

  // Convert route path into display pattern + regex using a fully linear,
  // character-by-character scan. No regex is compiled against user-derived
  // input, so this cannot exhibit super-linear backtracking (S5852).
  //
  // Placeholders `[slug]` are detected via indexOf and become:
  //   - `:slug` in the human-readable pattern
  //   - `([^/]+)` in the regex
  // All other literal characters are escaped one-by-one.
  const REGEX_SPECIALS = new Set([
    '.',
    '*',
    '+',
    '?',
    '^',
    '$',
    '{',
    '}',
    '(',
    ')',
    '|',
    '[',
    ']',
    '\\',
    '/',
  ]);
  const escapeChar = (c: string): string =>
    REGEX_SPECIALS.has(c) ? '\\' + c : c;
  const escapeLiteral = (s: string): string => {
    let out = '';
    for (const c of s) out += escapeChar(c);
    return out;
  };

  let patternBody = '';
  let regexBody = '';
  let cursor = 0;
  while (cursor < routePath.length) {
    const open = routePath.indexOf('[', cursor);
    if (open === -1) {
      const rest = routePath.slice(cursor);
      patternBody += rest;
      regexBody += escapeLiteral(rest);
      break;
    }
    const close = routePath.indexOf(']', open + 1);
    if (close === -1) {
      // Unterminated placeholder — treat remainder as literal
      const rest = routePath.slice(cursor);
      patternBody += rest;
      regexBody += escapeLiteral(rest);
      break;
    }
    // Literal prefix before '['
    const prefix = routePath.slice(cursor, open);
    patternBody += prefix;
    regexBody += escapeLiteral(prefix);
    // Placeholder name between [ and ]
    const name = routePath.slice(open + 1, close);
    patternBody += ':' + name;
    regexBody += '([^/]+)';
    cursor = close + 1;
  }

  const pattern = '/' + patternBody;
  const regexPattern = '^/' + regexBody + '$';

  const isDynamic = routePath.includes('[');

  // Import path relative to _routes.ts
  const importPath = './' + filePath.replace(/\.tsx$/, '');

  return {
    pattern,
    regex: regexPattern,
    importPath,
    isDynamic,
  };
}

function generateRoutesFile(routes: RouteInfo[]): string {
  // Sort routes: static first, then dynamic (more specific patterns first)
  routes.sort((a, b) => {
    if (a.isDynamic !== b.isDynamic) {
      return a.isDynamic ? 1 : -1;
    }
    // Longer patterns first (more specific)
    return b.pattern.length - a.pattern.length;
  });

  const imports = routes
    .map((r, i) => `import { default as Page${i} } from '${r.importPath}';`)
    .join('\n');

  const routeEntries = routes
    .map(
      (r, i) => `  {
    pattern: '${r.pattern}',
    regex: new RegExp('${r.regex}'),
    page: Page${i},
  }`,
    )
    .join(',\n');

  return `/**
 * Auto-generated route manifest
 * DO NOT EDIT - Generated by scripts/generate-routes.ts
 */

${imports}
import type { PageComponent } from '../lib/types';

export interface Route {
  pattern: string;
  regex: RegExp;
  page: PageComponent;
}

export const routes: Route[] = [
${routeEntries}
];

/**
 * Match URL to route
 */
export function matchRoute(url: string): Route | null {
  for (const route of routes) {
    if (route.regex.test(url)) {
      return route;
    }
  }
  return null;
}
`;
}

// Run generator
console.log('Scanning pages directory:', PAGES_DIR);
const routes = scanDirectory(PAGES_DIR);
console.log(`Found ${routes.length} routes:`);
routes.forEach((r) => console.log(`  ${r.pattern} → ${r.importPath}`));

const content = generateRoutesFile(routes);
writeFileSync(OUTPUT_FILE, content);
console.log(`\nGenerated: ${OUTPUT_FILE}`);
