/**
 * Index Barrel Generator
 *
 * Generates index.ts files that re-export all schemas in a source.
 *
 * Output: `export * from './schema1'; export * from './schema2'; ...`
 */

import type {
  GeneratorPlugin,
  FinalizeContext,
  GeneratedFile,
} from '../codegen/types';

// ============================================================================
// Options
// ============================================================================

export interface IndexBarrelOptions {
  /** File name for the barrel (default: 'index.ts') */
  filename?: string;
  /** Use named re-exports instead of star exports */
  namedExports?: boolean;
  /** Export types from .typed.ts files if they exist */
  includeTypedExports?: boolean;
  /** Add file header comment */
  header?: boolean;
  /** Import extension to use: '.ts' for Node.js native, '' for bundlers (default: '' for bundler compatibility) */
  importExtension?: '.ts' | '';
}

// ============================================================================
// Generator
// ============================================================================

/**
 * Create an index barrel generator plugin
 *
 * This generator runs in finalize() after all schemas are processed.
 * It generates an index.ts that re-exports all schemas.
 *
 * @example
 * ```ts
 * import { rawSchema, indexBarrel } from '@abapify/ts-xsd/generators';
 *
 * export default defineConfig({
 *   generators: [
 *     rawSchema(),
 *     indexBarrel(),  // Generates index.ts with all exports
 *   ],
 * });
 * ```
 */
export function indexBarrel(options: IndexBarrelOptions = {}): GeneratorPlugin {
  const {
    filename = 'index.ts',
    importExtension = '', // Default to extensionless for bundler compatibility
    namedExports = false,
    includeTypedExports = false,
    header = true,
  } = options;

  return {
    name: 'index-barrel',

    finalize(ctx: FinalizeContext): GeneratedFile[] {
      const files: GeneratedFile[] = [];

      // Generate one index per source
      for (const [sourceName, schemas] of ctx.processedSchemas) {
        const source = ctx.sources[sourceName];
        if (!source) continue;

        const lines: string[] = [];

        // Header
        if (header) {
          lines.push(
            '/**',
            ` * Auto-generated index for ${sourceName} schemas`,
            ' * ',
            ' * DO NOT EDIT - Generated by ts-xsd codegen',
            ' */',
            '',
          );
        }

        // Sort schemas alphabetically for consistent output
        const sortedSchemas = [...schemas].sort((a, b) =>
          a.name.localeCompare(b.name),
        );

        // Generate exports
        for (const schema of sortedSchemas) {
          if (namedExports) {
            const exportName = toValidIdentifier(schema.name);
            lines.push(
              `export { default as ${exportName} } from './${schema.name}${importExtension}';`,
            );
          } else {
            lines.push(`export * from './${schema.name}${importExtension}';`);
          }

          // Also export from typed files if requested
          if (includeTypedExports) {
            const typeName = pascalCase(schema.name);
            lines.push(
              `export type { ${typeName} } from './${schema.name}.typed${importExtension}';`,
            );
          }
        }

        lines.push('');

        files.push({
          path: filename,
          content: lines.join('\n'),
        });
      }

      return files;
    },
  };
}

// ============================================================================
// Helpers
// ============================================================================

const RESERVED_WORDS = new Set([
  'break',
  'case',
  'catch',
  'continue',
  'debugger',
  'default',
  'delete',
  'do',
  'else',
  'finally',
  'for',
  'function',
  'if',
  'in',
  'instanceof',
  'new',
  'return',
  'switch',
  'this',
  'throw',
  'try',
  'typeof',
  'var',
  'void',
  'while',
  'with',
  'class',
  'const',
  'enum',
  'export',
  'extends',
  'import',
  'super',
  'implements',
  'interface',
  'let',
  'package',
  'private',
  'protected',
  'public',
  'static',
  'yield',
  'await',
  'null',
  'true',
  'false',
]);

function toValidIdentifier(name: string): string {
  // Convert hyphens to camelCase
  let result = name.replaceAll(/-([a-zA-Z])/g, (_, c) => c.toUpperCase());
  // Escape reserved words
  if (RESERVED_WORDS.has(result)) {
    result = `${result}_`;
  }
  return result;
}

function pascalCase(str: string): string {
  return str
    .replaceAll(/[-_\s]+(.)?/g, (_, c) => (c ? c.toUpperCase() : ''))
    .replace(/^./, (s) => s.toUpperCase());
}
