/**
 * This file is part of the NocoBase (R) project.
 * Copyright (c) 2020-2024 NocoBase Co., Ltd.
 * Authors: NocoBase Team.
 *
 * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
 * For more information, please refer to: https://www.nocobase.com/agreement.
 */

import react from '@vitejs/plugin-react';
import fg from 'fast-glob';
import fs from 'fs-extra';
import path from 'path';
import { build as tsupBuild } from 'tsup';
import { build as viteBuild } from 'vite';
import { libInjectCss } from 'vite-plugin-lib-inject-css';

import { globExcludeFiles } from './constant';
import { PkgLog, UserConfig, getEnvDefine } from './utils';
import { rspack } from '@rspack/core';

export async function buildClient(cwd: string, userConfig: UserConfig, sourcemap: boolean = false, log: PkgLog) {
  log('build client');
  const cwdWin = cwd.replaceAll(/\\/g, '/');
  const cwdUnix = cwd.replaceAll(/\//g, '\\');
  const external = function (id: string) {
    if (id.startsWith('.') || id.startsWith(cwdUnix) || id.startsWith(cwdWin)) {
      return false;
    }
    return true;
  };
  await buildClientEsm(cwd, userConfig, sourcemap, external, log);
  await buildClientLib(cwd, userConfig, sourcemap, external, log);
  await buildLocale(cwd, userConfig, log);
}

type External = (id: string) => boolean;

function buildClientEsm(cwd: string, userConfig: UserConfig, sourcemap: boolean, external: External, log: PkgLog) {
  log('build client esm');
  // const entry = path.join(cwd, 'src/index.ts').replaceAll(/\\/g, '/');
  // const outDir = path.resolve(cwd, 'es');

  // return rspack({
  //   entry: {
  //     index: entry,
  //   },
  //   output: {
  //     path: outDir,
  //     library: {
  //       type: 'module',
  //     },
  //     clean: true,
  //   },
  //   target: ['es2015', 'web'],
  //   mode: process.env.NODE_ENV === 'production' ? 'production' : 'development',
  //   optimization: {
  //     minimize: process.env.NODE_ENV === 'production',
  //     moduleIds: 'deterministic',
  //     sideEffects: true,
  //   },
  //   resolve: {
  //     tsConfig: path.join(process.cwd(), 'tsconfig.json'),
  //     extensions: ['.js', '.jsx', '.ts', '.tsx', '.json', '.less', '.css'],
  //   },
  //   module: {
  //     rules: [
  //       {
  //         test: /\.less$/,
  //         use: [
  //           { loader: 'style-loader' },
  //           { loader: 'css-loader' },
  //           { loader: require.resolve('less-loader') },
  //           {
  //             loader: 'postcss-loader',
  //             options: {
  //               postcssOptions: {
  //                 plugins: {
  //                   'postcss-preset-env': {
  //                     browsers: ['last 2 versions', '> 1%', 'cover 99.5%', 'not dead'],
  //                   },
  //                   autoprefixer: {},
  //                 },
  //               },
  //             },
  //           },
  //         ],
  //         type: 'javascript/auto',
  //       },
  //       {
  //         test: /\.css$/,
  //         use: [
  //           'style-loader',
  //           'css-loader',
  //           {
  //             loader: 'postcss-loader',
  //             options: {
  //               postcssOptions: {
  //                 plugins: {
  //                   'postcss-preset-env': {
  //                     browsers: ['last 2 versions', '> 1%', 'cover 99.5%', 'not dead'],
  //                   },
  //                   autoprefixer: {},
  //                 },
  //               },
  //             },
  //           },
  //         ],
  //         type: 'javascript/auto',
  //       },
  //       {
  //         test: /\.(png|jpe?g|gif)$/i,
  //         type: 'asset',
  //       },
  //       {
  //         test: /\.svg$/i,
  //         issuer: /\.[jt]sx?$/,
  //         use: ['@svgr/webpack'],
  //       },
  //       {
  //         test: /\.jsx$/,
  //         exclude: /[\\/]node_modules[\\/]/,
  //         loader: 'builtin:swc-loader',
  //         options: {
  //           sourceMap: true,
  //           jsc: {
  //             parser: {
  //               syntax: 'ecmascript',
  //               jsx: true,
  //             },
  //             target: 'es5',
  //           },
  //         },
  //       },
  //       {
  //         test: /\.tsx$/,
  //         exclude: /[\\/]node_modules[\\/]/,
  //         loader: 'builtin:swc-loader',
  //         options: {
  //           sourceMap: true,
  //           jsc: {
  //             parser: {
  //               syntax: 'typescript',
  //               tsx: true,
  //             },
  //             target: 'es5',
  //           },
  //         },
  //       },
  //       {
  //         test: /\.ts$/,
  //         exclude: /[\\/]node_modules[\\/]/,
  //         loader: 'builtin:swc-loader',
  //         options: {
  //           sourceMap: true,
  //           jsc: {
  //             parser: {
  //               syntax: 'typescript',
  //             },
  //             target: 'es5',
  //           },
  //         },
  //       },
  //     ],
  //   },
  //   externals: [
  //     function ({ request }, callback) {
  //       if (external(request)) {
  //         return callback(null, true);
  //       }
  //       callback();
  //     }
  //   ],
  //   plugins: [
  //     new rspack.DefinePlugin(getEnvDefine()),
  //   ],
  //   stats: 'errors-warnings',
  // });

  const entry = path.join(cwd, 'src/index.ts').replaceAll(/\\/g, '/');
  const outDir = path.resolve(cwd, 'es');
  return viteBuild(
    userConfig.modifyViteConfig({
      mode: process.env.NODE_ENV || 'production',
      define: getEnvDefine(),
      build: {
        minify: process.env.NODE_ENV === 'production',
        outDir,
        cssCodeSplit: true,
        emptyOutDir: true,
        sourcemap,
        lib: {
          entry,
          formats: ['es'],
          fileName: 'index',
        },
        target: ['es2015', 'edge88', 'firefox78', 'chrome87', 'safari14'],
        rollupOptions: {
          cache: true,
          treeshake: true,
          external,
        },
      },
      plugins: [react(), libInjectCss()],
    }),
  );
}

async function buildClientLib(
  cwd: string,
  userConfig: UserConfig,
  sourcemap: boolean,
  external: External,
  log: PkgLog,
) {
  log('build client lib');
  const outDir = path.resolve(cwd, 'lib');
  const esDir = path.resolve(cwd, 'es');
  const entry = path.join(esDir, 'index.ts');

  fs.removeSync(entry);
  fs.linkSync(path.join(cwd, 'es/index.mjs'), entry);

  await viteBuild(
    userConfig.modifyViteConfig({
      mode: process.env.NODE_ENV || 'production',
      esbuild: {
        format: 'cjs',
      },
      build: {
        outDir,
        minify: process.env.NODE_ENV === 'production',
        sourcemap,
        lib: {
          entry: path.join(cwd, 'es/index.ts'),
          formats: ['cjs'],
          fileName: 'index',
        },
        rollupOptions: {
          external,
        },
      },
    }),
  );

  fs.removeSync(entry);

  const css = fg.sync('*.css', { cwd: esDir, absolute: true });
  css.forEach((file) => {
    fs.copySync(file, path.join(outDir, path.basename(file)));
  });
}

export function buildLocale(cwd: string, userConfig: UserConfig, log: PkgLog) {
  log('build client locale');

  const entry = fg.globSync(['src/locale/**', ...globExcludeFiles], { cwd, absolute: true });
  const outDir = path.resolve(cwd, 'lib', 'locale');
  return tsupBuild(
    userConfig.modifyTsupConfig({
      entry,
      splitting: false,
      clean: false,
      bundle: false,
      silent: true,
      treeshake: false,
      target: 'node16',
      keepNames: true,
      outDir,
      format: 'cjs',
      skipNodeModulesBundle: true,
      loader: { '.json': 'copy' },
    }),
  );
}
