/**
 * Copyright Super iPaaS Integration LLC, an IBM Company 2024
 */
import { APIAsset, RefModel, BaseAsset } from "../model/assets-model.js";
import { checkForNullOrUndefined } from "../helpers/common/data-helper.js";
import { showWarning } from "../helpers/common/message-helper.js";
import { AssetCacheModel } from "../model/asset-cache-model.js";
import { findPolicyKind, Kinds } from "../helpers/apim/asset-kinds/policy-helper.js";

const getRefsFromApiAsset = (asset: BaseAsset): AssetCacheModel[] => {
  const apiAsset = asset as unknown as APIAsset;
  const dependentAssets: AssetCacheModel[] = [];

  const dependentPolicySequenceAssets = checkPolicySequence(apiAsset);
  dependentAssets.push(...dependentPolicySequenceAssets);
  
  // Also check for properties references
  const dependentPropertiesAssets = checkProperties(apiAsset);
  dependentAssets.push(...dependentPropertiesAssets);

  // Also check for uriSchemes references
  const dependentUriSchems = checkuriSchemes(apiAsset);
  dependentAssets.push(...dependentUriSchems);

  // Also check for CORS references
  const dependentCORS = checkCORS(apiAsset);
  dependentAssets.push(...dependentCORS);

// Also check for scopes references
  const dependentScopes = checkScopes(apiAsset);
  dependentAssets.push(...dependentScopes);


  return dependentAssets;
};

const getAPIDefPath = (asset: BaseAsset): string | undefined => {
  const apiAsset = asset as unknown as APIAsset;
  const spec = checkForNullOrUndefined(
    apiAsset.spec,
    `Spec is not defined for the asset with kind 'API' and name '${apiAsset.metadata?.name}'`
  );
  const apiSpec = checkForNullOrUndefined(
    spec["api-spec"],
    `Attribute 'api-spec' is not defined
	for kind 'API' and name '${apiAsset.metadata?.name}'`
  );
  return apiSpec.$path;
};

const checkPolicySequence = (apiAsset: APIAsset): AssetCacheModel[] => {
  let spec = null;
  try {
    spec = checkForNullOrUndefined(
      apiAsset.spec,
      `Spec is not defined for the asset with kind 'API' and name '${apiAsset.metadata?.name}'`
    );
  } catch (error: unknown) {
    showWarning((error as Error).message);
    return [];
  }
  
  const policySeq: RefModel[] = spec["policy-sequence"];
  let policyKind=findPolicyKind(apiAsset);
  return policySeq.map((pSeq) => {
    return {
     kind: policyKind,
      ref: pSeq.$ref,
      isNewlyAdded: true,
    };
  });
};

const checkProperties = (apiAsset: APIAsset): AssetCacheModel[] => {
  let spec = null;
  try {
    spec = checkForNullOrUndefined(
      apiAsset.spec,
      `Spec is not defined for the asset with kind 'API' and name '${apiAsset.metadata?.name}'`
    );
  } catch (error: unknown) {
    showWarning((error as Error).message);
    return [];
  }
  // Use type assertion to access properties that might not be in the type definition
  const properties = (spec as any).properties;
  if (!properties) {
    return [];
  }
  const policySeq: RefModel[] = properties as RefModel[];
  return policySeq.map((pSeq) => {
    return {
      kind: 'properties',
      ref: pSeq.$ref,
      isNewlyAdded: true,
    };
  });
};

const checkuriSchemes = (apiAsset: APIAsset): AssetCacheModel[] => {
  let spec = null;
  try {
    spec = checkForNullOrUndefined(
      apiAsset.spec,
      `Spec is not defined for the asset with kind 'API' and name '${apiAsset.metadata?.name}'`
    );
  } catch (error: unknown) {
    showWarning((error as Error).message);
    return [];
  }
  // Use type assertion to access properties that might not be in the type definition
  const uriSchemes = (spec as any).uriSchemes;
  if (!uriSchemes) {
    return [];
  }

  const policySeq: RefModel = uriSchemes as RefModel;
  return [{
      kind: 'URISchemes',
      ref: policySeq.$ref,
      isNewlyAdded: true,
  }];
};

const checkCORS = (apiAsset: APIAsset): AssetCacheModel[] => {
  let spec = null;
  try {
    spec = checkForNullOrUndefined(
      apiAsset.spec,
      `Spec is not defined for the asset with kind 'API' and name '${apiAsset.metadata?.name}'`
    );
  } catch (error: unknown) {
    showWarning((error as Error).message);
    return [];
  }
  // Use type assertion to access properties that might not be in the type definition
  const cors = (spec as any).cors;
  if (!cors) {
    return [];
  }
  const policySeq: RefModel = cors as RefModel;
  return [{
       kind: 'CORS',
      ref: policySeq.$ref,
      isNewlyAdded: true,
  }];
};

const checkScopes = (apiAsset: APIAsset): AssetCacheModel[] => {
  let spec = null;
  try {
    spec = checkForNullOrUndefined(
      apiAsset.spec,
      `Spec is not defined for the asset with kind 'API' and name '${apiAsset.metadata?.name}'`
    );
  } catch (error: unknown) {
    showWarning((error as Error).message);
    return [];
  }
  // Use type assertion to access properties that might not be in the type definition
  const scopes = (spec as any).scopes;
  if (!scopes) {
    return [];
  }
  const policySeq: RefModel[] = scopes as RefModel[];
  return policySeq.map((pSeq) => {
    return {
      kind: 'scopes',
      ref: pSeq.$ref,
      isNewlyAdded: true,
    };
  });
};

export { getRefsFromApiAsset, getAPIDefPath };
