/**
 * Copyright Super iPaaS Integration LLC, an IBM Company 2024
 */
import { showError, showInfo } from "../../helpers/common/message-helper.js";
import {
  checkForRootDirPermission,
  checkIfProjectExists,
  checkIfRootDirExists,
} from "../../helpers/apim/root-dir-helper.js";
import {
  ASSERT_ADDED,
  CHECKING_FOR_PROJECT,
  CHECKING_ROOT_DIRECTORY,
  SPEC_ADDED,
} from "../../constants/message-constants.js";
import {
  checkAndLoadDependencies,
  searchAsset,
} from "../../helpers/apim/build-helper.js";
import AdmZip from "adm-zip";
import fs from 'fs';
import { KindEnums } from "@apic/api-model/common/StudioEnums.js";
import {
  getParentDir,
  getSubDirectory,
  normalizePath,
  readFile,
} from "../../helpers/common/fs-helper.js";
import { APIM_MODE, COMMA } from "../../constants/app-constants.js";
import {
  checkForNullOrUndefined,
  isNullOrUndefined,
} from "../../helpers/common/data-helper.js";
import path from "path";
import { cropPrefix } from "../../helpers/common/string-helper.js";
import { readYaml } from "../../helpers/common/yaml-helper.js";
import { getAPIDefPath } from "../../handlers/api-asset-handler.js";
import { BaseAsset } from "../../model/assets-model.js";
import { processProjectBuild } from "@apic/studio-build";
import { DebugManager } from "../../debug/debug-manager.js";
import { AssetCache } from "../../cache/asset-cache.js";

const executeBuildProjectAssets = async (
  project: string,
  rootDirPath: string,
  assets: string
): Promise<Buffer> => {
  try {

  AssetCache.getInstance().clear();
	AssetCache.getInstance().setProjectNames(project);
	AssetCache.getInstance().setRootDirPath(rootDirPath);
    /* (*) Validate rootDirPath */
    if (DebugManager.getInstance().isDebugEnabled()) {
      showInfo(CHECKING_ROOT_DIRECTORY);
    }
    checkIfRootDirExists(rootDirPath);
    checkForRootDirPermission(rootDirPath);

    /* (*) Validate projectNames */
    if (DebugManager.getInstance().isDebugEnabled()) {
      showInfo(CHECKING_FOR_PROJECT);
    }
    checkIfProjectExists(rootDirPath, project);

    /* (*) Iterate and build project archive */
    const zipFile = new AdmZip();
    checkAndAddAssets(assets, project, rootDirPath, zipFile);

    /* (*) Check and Load Dependencies */
    checkAndLoadDependencies(rootDirPath, project, zipFile, false);


    /* (*) Save zip file to current directory for debugging */
    const zipBuffer = zipFile.toBuffer();

    /* (*) Invoke Studio Build API */
    const response = await processProjectBuild(zipBuffer, APIM_MODE);
    if(response && response.success && response.data){
        return response.data;
    }

    /* (*) If build failed, throw error */
    showError('Build failed: ' + (response?.errors || 'Unknown error'));
     process.exit(1);
    
  } catch (error: unknown) {
    showError((error as Error).message);
    
    process.exit(1);
  }
};

function addAssetDefinition(
  asset: string,
  projectDirPath: string,
  rootDirPath: string,
  zipFile: AdmZip
) {
  const result = searchAsset(KindEnums.API, asset, projectDirPath) as fs.Dirent;
  const zipPath = `${cropPrefix(
    result.parentPath,
    normalizePath(rootDirPath)
  )}`;
  const filePath = normalizePath(`${result.parentPath}/${result.name}`);
  zipFile.addLocalFile(filePath, zipPath);
  showInfo(ASSERT_ADDED + asset);
  return result;
}

function addAPIDefinition(
  result: fs.Dirent,
  asset: string,
  rootDirPath: string,
  projectDirPath: string,
  zipFile: AdmZip
) {
  let $path = getAPIDefPath(
    readYaml<BaseAsset>(readFile(result.parentPath, result.name))
  );
  $path = checkForNullOrUndefined(
    $path,
    `API Definition Path is not found for ${asset}`
  );
  let normalizedAPIDefinitionPath = '';
  if($path.startsWith('./')||$path.startsWith('../')){

    const zipPath = `${cropPrefix(
      result.parentPath,
      normalizePath(rootDirPath)
    )}`;
    const filePath=`${zipPath}/${result.name}`;
    const baseDir = path.dirname(filePath);
    const resolvedPath = path.join(baseDir, $path);
    normalizedAPIDefinitionPath = path.normalize(`${rootDirPath}${resolvedPath}`); 
  }
  else{
    normalizedAPIDefinitionPath=normalizePath(
    `${projectDirPath}/${$path}`
  );
}
  const zipPathForAPIDefinition = `${cropPrefix(
    getParentDir(normalizedAPIDefinitionPath),
    normalizePath(rootDirPath)
  )}`;
  zipFile.addLocalFile(normalizedAPIDefinitionPath, zipPathForAPIDefinition);
  showInfo(SPEC_ADDED + $path);
}

const checkAndAddAssets = (
  assets: string,
  project: string,
  rootDirPath: string,
  zipFile: AdmZip
) => {
  /* (*) check if API asset kinds exists in the given project */
  const projectDirPath = getSubDirectory(rootDirPath, project);
  const inValidAsset = assets
    .split(COMMA)
    .find((asset) =>
      isNullOrUndefined(searchAsset(KindEnums.API, asset, projectDirPath))
    );

  if (!isNullOrUndefined(inValidAsset)) {
    throw new Error(`Invalid asset of kind 'API' and name ${inValidAsset}`);
  }

  /* (*) add the asset files along with api specification */
  assets.split(COMMA).forEach((asset) => {
    // adding kind API
    const result = addAssetDefinition(
      asset,
      projectDirPath,
      rootDirPath,
      zipFile
    );

    //adding specification
    addAPIDefinition(result, asset, rootDirPath,projectDirPath, zipFile);
  });
};

export { executeBuildProjectAssets };
