import { defineConfig } from '@nocobase/build';
import fs from 'fs-extra';
import path from 'path';

async function generateIndexFiles(packageJsonPath: string) {
  // Read and parse package.json
  const packageJson = JSON.parse(await fs.readFile(packageJsonPath, 'utf-8'));
  const exports = packageJson.exports;

  // Collect all export paths excluding package.json
  const exportPaths = Object.entries(exports)
    .filter(([key]) => key !== './package.json')
    .map(([key, value]: [string, any]) => {
      // Remove './' prefix from the key
      const normalizedKey = key.startsWith('./') ? key.slice(2) : key;

      // Get the paths for different formats
      const paths = {
        js: typeof value === 'object' ? value.import?.replace(/^\.\//, '') : value?.replace(/^\.\//, ''),
        dts: typeof value === 'object' ? value.types?.import?.replace(/^\.\//, '') : null,
      };

      return { key: normalizedKey, paths };
    });

  // Generate JavaScript index content
  const jsContent = `// This file is auto-generated from package.json exports
// Do not edit this file manually

${exportPaths.map(({ key, paths }) => `export * from './${paths.js.replace(/\.js$/, '')}';`).join('\n')}
`;

  // Generate CommonJS index content
  const cjsContent = `// This file is auto-generated from package.json exports
// Do not edit this file manually

${exportPaths.map(({ key, paths }) => `module.exports = require('../${paths.js.replace(/\.js$/, '')}');`).join('\n')}
`;

  // Generate TypeScript declaration content
  const dtsContent = `// This file is auto-generated from package.json exports
// Do not edit this file manually

${exportPaths
  .map(({ key, paths }) => {
    const dtsPath = paths.dts?.replace(/\.d\.ts$/, '') || paths.js.replace(/\.js$/, '');
    return `export * from './${dtsPath}';`;
  })
  .join('\n')}
`;

  // Generate CommonJS declaration content
  const ctsContent = `// This file is auto-generated from package.json exports
// Do not edit this file manually

${exportPaths
  .map(({ key, paths }) => {
    const dtsPath = paths.dts?.replace(/\.d\.ts$/, '') || paths.js.replace(/\.js$/, '');
    return `export * from './${dtsPath}';`;
  })
  .join('\n')}
`;

  // Generate package.json exports for index files
  const indexExports = {
    '.': {
      types: {
        import: './index.d.ts',
        require: './index.d.cts',
        default: './index.d.ts',
      },
      import: './index.js',
      require: './index.cjs',
    },
    ...exports, // Keep existing exports
  };

  return {
    js: jsContent,
    cjs: cjsContent,
    dts: dtsContent,
    cts: ctsContent,
    exports: indexExports,
  };
}

async function writeIndexFiles(pkgPath: string) {
  try {
    const contents = await generateIndexFiles(pkgPath);
    const outputDir = path.dirname(pkgPath);

    // Write index.js
    await fs.writeFile(path.join(outputDir, 'index.js'), contents.js);
    await fs.writeFile(path.join(outputDir, 'dist', 'index.js'), contents.js);
    console.log('Generated index.js');

    // Write index.js
    await fs.writeFile(path.join(outputDir, 'index.cjs'), contents.cjs);
    await fs.writeFile(path.join(outputDir, 'dist', 'index.cjs'), contents.cjs);
    console.log('Generated index.cjs');

    // Write index.d.ts
    await fs.writeFile(path.join(outputDir, 'index.d.ts'), contents.dts);
    await fs.writeFile(path.join(outputDir, 'dist', 'index.d.ts'), contents.dts);
    console.log('Generated index.d.ts');

    // Write index.d.cts
    await fs.writeFile(path.join(outputDir, 'index.d.cts'), contents.cts);
    console.log('Generated index.d.cts');

    // Update package.json with new exports
    const packageJson = JSON.parse(await fs.readFile(pkgPath, 'utf-8'));
    packageJson.exports = contents.exports;
    await fs.writeFile(pkgPath, JSON.stringify(packageJson, null, 2) + '\n');
    console.log('Updated package.json exports');
  } catch (error) {
    console.error('Error generating index files:', error);
  }
}

export default defineConfig({
  beforeBuild: async (log) => {
    await fs.promises.rm(path.resolve(__dirname, 'dist'), { recursive: true, force: true });
    const pkgPath = path.resolve(process.cwd(), 'node_modules/@langchain/core/package.json');
    await writeIndexFiles(pkgPath);
  },

  afterBuild: async (log) => {
    log('copying deps');
    const deps = [
      'decamelize',
      'zod',
      'zod-to-json-schema',
      'langsmith',
      'p-retry',
      'p-queue',
      'p-timeout',
      'p-finally',
      'mustache',
      // 'js-tiktoken/lite',
      '@cfworker/json-schema',
    ];
    for (const dep of deps) {
      const depPath = path.resolve(process.cwd(), 'node_modules', dep);
      await fs.promises.cp(depPath, path.resolve(__dirname, 'dist/node_modules/@langchain/core/node_modules', dep), {
        recursive: true,
        force: true,
      });
    }
    log('copying js-tiktoken/lite');
    const files = ['lite.d.ts', 'lite.js', 'lite.cjs'];
    for (const file of files) {
      const depPath = path.dirname(require.resolve('js-tiktoken/lite'));
      const filePath = path.resolve(depPath, file);
      await fs.promises.cp(
        filePath,
        path.resolve(__dirname, 'dist/node_modules/@langchain/core/node_modules/js-tiktoken', file),
        {
          recursive: true,
          force: true,
        },
      );
    }
  },
});
