/**
 * ts-xsd Codegen Configuration for adt-schemas
 *
 * Generates raw schema literals and TypeScript interfaces from SAP ADT XSD files.
 * Following the same pattern as adt-plugin-abapgit.
 *
 * Output structure:
 *   src/schemas/generated/
 *   ├── schemas/
 *   │   ├── sap/
 *   │   ├── custom/
 *   │   └── index.ts
 *   ├── types/
 *   │   ├── sap/
 *   │   ├── custom/
 *   │   └── index.ts
 *   └── index.ts
 *
 * Usage:
 *   npx nx run adt-schemas:codegen
 */

import {
  defineConfig,
  rawSchema,
  interfaces,
} from '@abapify/ts-xsd/generators';
import { deriveRootTypeName } from '@abapify/ts-xsd';

// Target schemas - exported with typed wrappers
// Dependencies are auto-discovered via autoLink from XSD imports
const targetSchemas = [
  // SAP schemas
  'sap/atom',
  'sap/adtcore',
  'sap/exception', // ADT error response format
  'sap/classes',
  'sap/interfaces',
  'sap/packagesV1',
  'sap/programs', // ABAP programs
  'sap/includes', // ABAP program includes
  'sap/groups', // Function groups
  'sap/fmodules', // Function modules
  'sap/fincludes', // Function group includes
  'sap/atc',
  'sap/atcexemption',
  'sap/atcfinding',
  'sap/atcinfo',
  'sap/atcobject',
  'sap/atcresult',
  'sap/atcresultquery',
  'sap/atctagdescription',
  'sap/atcworklist',
  'sap/transportmanagment',
  'sap/transportsearch',
  'sap/configuration',
  'sap/configurations',
  'sap/checkrun',
  'sap/checklist',
  'sap/debugger',
  'sap/logpoint',
  'sap/traces',
  'sap/quickfixes',
  'sap/log',
  'sap/templatelink',
  // Data Dictionary
  'sap/domain',
  'sap/dataelements',
  'sap/tabletype',
  'sap/tablesettings',
  // Business services
  'sap/servicebinding', // RAP Service Binding (SRVB)
  // Custom schemas
  'custom/dataelementWrapper', // DTEL wrapper (SAP wraps inner dtel:dataElement in blue:wbobj)
  'custom/blueSource', // TABL/Structure wrapper (SAP uses blue:blueSource extending AbapSourceMainObject)
  'custom/atomExtended',
  'custom/discovery',
  'custom/http',
  'custom/templatelinkExtended',
  'custom/transportfind',
  'custom/transportmanagmentCreate',
  'custom/transportmanagmentSingle',
  'custom/atcRun',
  'custom/aunitRun',
  'custom/aunitResult',
  'custom/atomFeed',
  'custom/objectProperties',
  'custom/transportUseraction',
  'custom/ddlSource',
  'custom/dclSource',
  'custom/srvdSource',
  'custom/acoverageResult',
  'custom/acoverageStatements',
  'custom/badi', // BAdI / Enhancement Implementation (ENHO) wrapper
];

export default defineConfig({
  // Use extensionless imports for bundler compatibility
  importExtension: '',
  // Clean output directory before generating
  clean: true,
  sources: {
    // Single source with path-based schema names
    xsd: {
      xsdDir: '.xsd',
      outputDir: 'src/schemas/generated/schemas',
      schemas: targetSchemas,
      autoLink: true, // Auto-discover dependencies from XSD imports
    },
  },
  generators: [
    // Generate raw schema literals with default export
    rawSchema({
      defaultExport: true,
      $xmlns: true,
      $imports: true,
      singleQuote: true,
    }),
    // Generate TypeScript interfaces to generated/types/ directory
    // Uses ts-morph type checker for accurate type expansion
    interfaces({
      filePattern: '../types/{name}.types.ts',
      flatten: true, // Generate single flattened type per file
      addJsDoc: true,
    }),
  ],

  // Generate schema and type index files
  afterAll({ sources }) {
    // Get all resolved schemas from context (includes auto-discovered dependencies)
    const allSchemas = sources.xsd.schemas as string[];

    // Split schemas by prefix (sap/, custom/)
    const sapSchemas = allSchemas
      .filter((s: string) => s.startsWith('sap/'))
      .map((s: string) => s.replace('sap/', ''));
    const customSchemas = allSchemas
      .filter((s: string) => s.startsWith('custom/'))
      .map((s: string) => s.replace('custom/', ''));

    // SAP schemas index
    const sapSchemasIndex = [
      '/**',
      ' * Auto-generated SAP schemas index',
      ' * DO NOT EDIT - Generated by ts-xsd codegen',
      ' */',
      '',
      ...sapSchemas.map(
        (s: string) =>
          `export { default as ${s.replaceAll('-', '')} } from './${s}';`,
      ),
      '',
    ].join('\n');

    // Custom schemas index
    const customSchemasIndex = [
      '/**',
      ' * Auto-generated custom schemas index',
      ' * DO NOT EDIT - Generated by ts-xsd codegen',
      ' */',
      '',
      ...customSchemas.map(
        (s: string) =>
          `export { default as ${s.replaceAll('-', '')} } from './${s}';`,
      ),
      '',
    ].join('\n');

    // Schemas aggregate index
    const schemasIndex = [
      '/**',
      ' * Auto-generated schema index',
      ' * DO NOT EDIT - Generated by ts-xsd codegen',
      ' */',
      '',
      `export * from './sap';`,
      `export * from './custom';`,
      '',
    ].join('\n');

    // Use the canonical deriveRootTypeName from ts-xsd (handles .xsd extension, paths, etc.)
    const toRootTypeName = (name: string) =>
      deriveRootTypeName(name) ?? `${name}Schema`;

    // Reserved words that can't be used as variable names
    const reservedWords = 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',
    ]);

    const toExportName = (name: string) => {
      const cleaned = name.replaceAll('-', '');
      return reservedWords.has(cleaned) ? `${cleaned}Schema` : cleaned;
    };

    // Filter to only target schemas (from targetSchemas list)
    const targetSapSchemas = targetSchemas
      .filter((s: string) => s.startsWith('sap/'))
      .map((s: string) => s.replace('sap/', ''));
    const targetCustomSchemas = targetSchemas
      .filter((s: string) => s.startsWith('custom/'))
      .map((s: string) => s.replace('custom/', ''));

    // Generate typed.ts - re-export raw schemas wrapped with typed()
    // Only TARGET schemas are exported, internal schemas are kept internal
    const typedLines: string[] = [
      '/**',
      ' * Auto-generated typed schema exports',
      ' * ',
      ' * DO NOT EDIT - Generated by ts-xsd codegen',
      ' * ',
      ' * Only target schemas are exported here.',
      ' * Internal schemas (xml, abapoo, etc.) are used for type resolution only.',
      ' * ',
      ' * @example',
      " * import { classes } from 'adt-schemas';",
      ' * const data = classes.parse(xml);  // data is fully typed!',
      ' */',
      '',
      `import { typedSchema, type TypedSchema } from '@abapify/ts-xsd';`,
      '',
    ];

    // Collect type imports - import directly from individual files
    const sapTypeImportLines: string[] = [];
    const customTypeImportLines: string[] = [];

    // Generate typed exports for TARGET SAP schemas only
    typedLines.push('// SAP schemas');
    for (const schemaName of targetSapSchemas) {
      const exportName = toExportName(schemaName);
      const importName = `_${schemaName.replaceAll('-', '')}`;
      const rootTypeName = toRootTypeName(schemaName);

      sapTypeImportLines.push(
        `import type { ${rootTypeName} } from './types/sap/${schemaName}.types';`,
      );
      typedLines.push(
        `import ${importName} from './schemas/sap/${schemaName}';`,
      );
      typedLines.push(
        `export const ${exportName}: TypedSchema<${rootTypeName}> = typedSchema<${rootTypeName}>(${importName});`,
      );
    }

    typedLines.push('');
    typedLines.push('// Custom schemas');

    // Generate typed exports for TARGET custom schemas only
    for (const schemaName of targetCustomSchemas) {
      const exportName = toExportName(schemaName);
      const importName = `_${schemaName.replaceAll('-', '')}`;
      const rootTypeName = toRootTypeName(schemaName);

      customTypeImportLines.push(
        `import type { ${rootTypeName} } from './types/custom/${schemaName}.types';`,
      );
      typedLines.push(
        `import ${importName} from './schemas/custom/${schemaName}';`,
      );
      typedLines.push(
        `export const ${exportName}: TypedSchema<${rootTypeName}> = typedSchema<${rootTypeName}>(${importName});`,
      );
    }

    typedLines.push('');

    // Insert type imports after the header (before SAP schemas section)
    const typeImportLines = [
      `// Pre-generated root schema types (imported from individual files)`,
      ...sapTypeImportLines,
      ...customTypeImportLines,
      '',
    ];
    // Find the index of '// SAP schemas' and insert before it
    const sapIndex = typedLines.findIndex((line) => line === '// SAP schemas');
    typedLines.splice(sapIndex, 0, ...typeImportLines);

    const typedIndex = typedLines.join('\n');

    // Main index - exports typed schemas only
    const mainIndex = [
      '/**',
      ' * Auto-generated schema index',
      ' * DO NOT EDIT - Generated by ts-xsd codegen',
      ' * ',
      ' * Typed schemas with parse/build methods.',
      ' * Each schema exports a corresponding Data type (e.g., DiscoveryData, ClassesData).',
      ' * ',
      ' * @example',
      " * import { classes, type ClassesData } from 'adt-schemas';",
      ' * ',
      ' * const data: ClassesData = classes.parse(xml);',
      ' */',
      '',
      `// Typed schemas with parse/build methods + inferred data types`,
      `export * from './typed';`,
      '',
    ].join('\n');

    return [
      {
        path: 'src/schemas/generated/schemas/sap/index.ts',
        content: sapSchemasIndex,
      },
      {
        path: 'src/schemas/generated/schemas/custom/index.ts',
        content: customSchemasIndex,
      },
      { path: 'src/schemas/generated/schemas/index.ts', content: schemasIndex },
      { path: 'src/schemas/generated/typed.ts', content: typedIndex },
      { path: 'src/schemas/generated/index.ts', content: mainIndex },
    ];
  },
});
