/**
 * Interfaces Generator
 *
 * Generates TypeScript interfaces from XSD schemas.
 * Uses ts-morph for TypeScript code generation.
 *
 * Two modes:
 * 1. flatten: false (default) - Generates interfaces with imports and extends
 * 2. flatten: true - Generates a single flattened type with all nested types inlined
 */

import type {
  GeneratorPlugin,
  TransformContext,
  GeneratedFile,
} from '../codegen/types';
import { generateInterfaces as generateInterfacesFromSchema } from '../codegen/interface-generator';
import { resolveSchema } from '../xsd/resolve';

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

export interface InterfacesOptions {
  /** Output file name pattern. Use {name} for schema name, {source} for source name */
  filePattern?: string;
  /** Add file header comment */
  header?: boolean;
  /**
   * If true, generates a single flattened type with all nested types inlined.
   * If false (default), generates interfaces with imports and extends.
   */
  flatten?: boolean;
  /** Custom root type name pattern. Use {name} for schema name (default: '{Name}Schema') */
  rootTypePattern?: string;
  /** Add JSDoc comments to generated types */
  addJsDoc?: boolean;
}

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

/**
 * Extract base name from schema name (handles paths like 'sap/atom' -> 'atom')
 */
function getBaseName(schemaName: string): string {
  const parts = schemaName.split('/');
  return parts.at(-1) ?? schemaName;
}

function deriveRootTypeName(schemaName: string, pattern: string): string {
  const baseName = getBaseName(schemaName);
  const capitalized = baseName.charAt(0).toUpperCase() + baseName.slice(1);
  return pattern.replace('{name}', baseName).replace('{Name}', capitalized);
}

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

/**
 * Create an interfaces generator plugin
 *
 * @example
 * ```ts
 * import { interfaces } from '@abapify/ts-xsd/generators';
 *
 * export default defineConfig({
 *   generators: [
 *     interfaces(),                    // interfaces with imports
 *     interfaces({ flatten: true }),   // fully flattened types
 *   ],
 * });
 * ```
 */
export function interfaces(options: InterfacesOptions = {}): GeneratorPlugin {
  const {
    filePattern = options.flatten ? '{name}.flattened.ts' : '{name}.types.ts',
    header = true,
    flatten = false,
    rootTypePattern = '{Name}Schema',
    addJsDoc = true,
  } = options;

  return {
    name: 'interfaces',

    transform(ctx: TransformContext): GeneratedFile[] {
      const { schema, source } = ctx;

      const rootTypeName = deriveRootTypeName(schema.name, rootTypePattern);

      // Always resolve the schema to merge all imports into one flat schema
      // This ensures all types are available in a single source file
      // keepImportsRef preserves $imports so element refs from imported schemas can be resolved
      const targetSchema = resolveSchema(schema.schema, {
        keepImportsRef: true,
      });

      // Check if resolved schema has root elements (check AFTER resolution for imported elements)
      const hasRootElements =
        targetSchema.element && targetSchema.element.length > 0;

      // When flatten=true, skip dependency schemas (no root elements)
      // Their types are already inlined into the schemas that use them
      if (flatten && !hasRootElements) {
        return []; // Skip - no file generated
      }

      // Generate interfaces
      // When flatten=false, disable root type generation (just interfaces)
      // When flatten=true, generate root type for the primary element
      const { code } = generateInterfacesFromSchema(targetSchema, {
        rootTypeName: flatten && hasRootElements ? rootTypeName : null,
        addJsDoc,
        flatten,
      });

      // Build output
      const lines: string[] = [];

      if (header) {
        lines.push(
          '/**',
          ' * Auto-generated TypeScript interfaces from XSD',
          ' * DO NOT EDIT - Generated by ts-xsd codegen',
          ` * Source: ${source.name}/${schema.name}.xsd`,
          flatten ? ' * Mode: Flattened' : ' * Mode: Interfaces',
          ' */',
          '',
        );
      }

      lines.push(code);

      const fileName = filePattern
        .replace('{name}', schema.name)
        .replace('{source}', source.name);

      return [
        {
          path: fileName,
          content: lines.join('\n'),
        },
      ];
    },
  };
}
