/**
 * Scaffolding utilities for mx CLI.
 *
 * Provides functions for creating package structures, templates, etc.
 */

import * as fs from 'node:fs';
import * as path from 'node:path';
import { validateManifestForMxCli } from './manifestValidator.js';

export interface ScaffoldOptions {
  name: string;
  description?: string;
  version?: string;
}

/**
 * Create a basic package structure.
 */
export function createPackageStructure(options: ScaffoldOptions): void {
  const root = path.resolve(options.name);
  const folders = ['src', 'examples', 'skills', 'tests'];
  fs.mkdirSync(root, { recursive: true });
  for (const folder of folders) {
    fs.mkdirSync(path.join(root, folder), { recursive: true });
  }
}

/**
 * Generate matrix.json content.
 */
export function generateMatrixJson(options: ScaffoldOptions): string {
  return JSON.stringify({
    name: options.name,
    version: options.version ?? '0.1.0',
    description: options.description ?? '',
    runtime: {
      language: 'typescript',
      entry: 'src/index.ts',
    },
    components: [],
    permissions: {
      fsPolicy: 'none',
    },
  }, null, 2);
}

export function toKebabCase(value: string): string {
  return value
    .trim()
    .replace(/([a-z0-9])([A-Z])/g, '$1-$2')
    .replace(/[\s_]+/g, '-')
    .replace(/-+/g, '-')
    .replace(/^-|-$/g, '')
    .toLowerCase();
}

export function toPascalCase(value: string): string {
  return value
    .trim()
    .replace(/[_-]+/g, ' ')
    .split(/\s+/)
    .filter(Boolean)
    .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
    .join('');
}

export function writeJsonFile(filePath: string, value: unknown): void {
  fs.mkdirSync(path.dirname(filePath), { recursive: true });
  fs.writeFileSync(filePath, JSON.stringify(value, null, 2) + '\n', 'utf8');
}

export function validateMatrixManifest(manifest: unknown): { valid: boolean; errors: string[] } {
  const result = validateManifestForMxCli(manifest);
  return { valid: result.valid, errors: result.errors };
}

/**
 * Generate package.json for a scaffolded package.
 */
export function generatePackageJson(name: string, options?: {
  webapp?: boolean;
  service?: boolean;
  scripts?: Record<string, string>;
}): Record<string, unknown> {
  const scripts: Record<string, string> = options?.scripts ?? (options?.webapp
    ? { dev: 'vite', build: 'vite build', test: 'node --import tsx --test tests/**/*.spec.ts' }
    : options?.service
      ? {
        build: 'tsc -p tsconfig.json',
        'build:watch': 'tsc -w -p tsconfig.json --preserveWatchOutput',
        dev: 'tsc -w -p tsconfig.json --preserveWatchOutput',
        test: 'node --import tsx --test tests/**/*.spec.ts',
      }
    : { build: 'tsc', test: 'node --import tsx --test tests/**/*.spec.ts' });

  const dependencies: Record<string, string> = {};
  const devDependencies: Record<string, string> = {
    'typescript': '^5.0.0',
  };

  if (options?.service) {
    dependencies['@open-matrix/core'] = '*';
  } else {
    devDependencies['@open-matrix/core'] = '*';
  }

  if (options?.webapp) {
    devDependencies['@open-matrix/federation'] = '*';
    devDependencies['vite'] = '^5.0.0';
    devDependencies['nats'] = '^5.0.0';
  }

  return {
    name: `@matrix/${name}`,
    version: '0.1.0',
    type: 'module',
    files: [
      'dist',
      'matrix.json',
    ],
    scripts,
    ...(Object.keys(dependencies).length > 0 ? { dependencies } : {}),
    devDependencies,
  };
}

/**
 * Generate tsconfig.json for a scaffolded package.
 */
export function generateTsconfig(options?: { webapp?: boolean; service?: boolean }): Record<string, unknown> {
  const compilerOptions: Record<string, unknown> = {
    target: 'ES2022',
    module: 'NodeNext',
    moduleResolution: 'NodeNext',
    outDir: 'dist',
    rootDir: 'src',
    declaration: true,
    strict: true,
    esModuleInterop: true,
    skipLibCheck: true,
  };

  if (options?.service) {
    compilerOptions.incremental = true;
    compilerOptions.tsBuildInfoFile = '.tsbuildinfo';
    compilerOptions.sourceMap = true;
  }

  if (options?.webapp) {
    compilerOptions.module = 'ESNext';
    compilerOptions.moduleResolution = 'Bundler';
    compilerOptions.noEmit = true;
    compilerOptions.lib = ['ES2022', 'DOM', 'DOM.Iterable'];
    delete compilerOptions.outDir;
    delete compilerOptions.rootDir;
    delete compilerOptions.declaration;
  }

  return {
    compilerOptions,
    include: ['src'],
  };
}
