/**
 * Copyright (c) 2025 Huawei Technologies Co., Ltd.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import Case from 'case';
import { execaCommandSync, execa, execaSync } from 'execa';
import pathUtils from 'path';
import { AbsolutePath } from '../src/core';
export class ReactNativeFixture {
  private cwd: string;
  constructor(cwd: string | AbsolutePath) {
    if (cwd instanceof AbsolutePath) {
      this.cwd = cwd.getValue();
    } else {
      this.cwd = cwd;
    }
  }

  help() {
    return execaCommandSync(`react-native --help`).stdout;
  }

  initHarmony(args: {
    projectRootPath: string;
    bundleName: string;
    appName?: string;
    rnohNpmPackageName?: string;
    rnohCliNpmPackageName?: string;
  }): {
    stdout: string;
    stderr: string;
  } {
    return execaCommandSync(
      `react-native init-harmony ${this.createCliArgs(args)}`,
      { env: { FORCE_COLOR: '0' } }
    );
  }

  packHarmony(args: {
    harmonyDirPath: string;
    ohModulePath: string;
    packageJSONPath: string;
  }) {
    return execaCommandSync(
      `react-native pack-harmony --harmony-dir-path ${this.useCwd(
        args.harmonyDirPath
      )} --oh-module-path ${this.useCwd(
        args.ohModulePath
      )} --package-json-path ${this.useCwd(args.packageJSONPath)}`
    ).stdout;
  }
  unpackHarmony(args: { projectRootPath: string; outputDir: string }) {
    return execaSync(
      'react-native',
      [
        'unpack-harmony',
        '--project-root-path',
        this.useCwd(args.projectRootPath),
        '--output-dir',
        this.useCwd(args.outputDir),
      ],
      {
        env: { FORCE_COLOR: '0' },
        shell: true,
      }
    ).stdout;
  }

  createMetroHostConstantsHarmony(args: { output: string }) {
    return execaCommandSync(
      `react-native create-metro-host-constants-harmony --output ${this.useCwd(
        args.output
      )}`
    ).stdout;
  }

  codegenHarmony(args: {
    cppOutputPath: string;
    projectRootPath: string;
    rnohModulePath?: string;
  }) {
    return execaCommandSync(
      `react-native codegen-harmony --no-safety-check --cpp-output-path ${this.useCwd(
        args.cppOutputPath
      )} --project-root-path ${this.useCwd(
        args.projectRootPath
      )} --rnoh-module-path ${this.useCwd(
        args.rnohModulePath ?? './harmony/rnoh'
      )}`
    ).stdout;
  }

  runHarmony(args: { help: true }) {
    return execaCommandSync(
      `react-native run-harmony ${this.createCliArgs(args)}`
    ).stdout;
  }

  codegenLibHarmony(
    args:
      | { help: true }
      | {
          npmPackageName: string;
          cppOutputPath: string;
          etsOutputPath: string;
          cppComponentsSpecPaths?: string;
          arktsComponentsSpecPaths?: string;
          turboModulesSpecPaths?: string;
          noSafetyCheck?: boolean;
        }
  ) {
    return execaCommandSync(
      `react-native codegen-lib-harmony ${this.createCliArgs(args)}`
    ).stdout;
  }

  private createCliArgs(
    args: Record<string, string | number | boolean>
  ): string {
    return Object.entries(args)
      .filter(([_, value]) => {
        if (typeof value === 'boolean') {
          return value;
        }
        return value !== undefined && value !== null;
      })
      .map(([key, value]) => {
        const formattedKey = Case.kebab(key);

        if (typeof value === 'boolean') {
          return `--${formattedKey}`;
        }

        if (
          (key.endsWith('Path') || key.endsWith('Paths')) &&
          typeof value === 'string'
        ) {
          return `--${formattedKey} ${this.useCwd(value)}`;
        }

        return `--${formattedKey} ${value}`;
      })
      .join(' ');
  }

  private useCwd(relPath: string) {
    return pathUtils.join(this.cwd, relPath);
  }
}