import { findPluginByIdentifier } from "@applicaster/zapp-react-native-utils/pluginUtils";
import { appStore } from "@applicaster/zapp-react-native-redux/AppStore";
import { loggerLiveImageManager } from "../../../VideoLive/loggerHelper";

const { log_debug, log_error } = loggerLiveImageManager;

export type PreloadHookConfig = ZappPreloadPlugins & {
  configuration: any;
};

function runHookWithCallback(
  invoke: (
    payload: any,
    callback: (result: hookCallbackArgs) => void,
    abortCallback: () => void
  ) => void,
  payload: any
): Promise<{ payload: any; aborted: boolean }> {
  return new Promise((resolve, reject) => {
    const abortCallback = () => {
      resolve({ payload, aborted: true });
    };

    try {
      invoke(
        payload,
        ({
          success,
          error,
          payload: resultPayload,
          abort,
        }: hookCallbackArgs) => {
          if (error) {
            reject(error);
          } else if (!success || abort) {
            resolve({ payload: resultPayload ?? payload, aborted: true });
          } else {
            resolve({ payload: resultPayload ?? payload, aborted: false });
          }
        },
        abortCallback
      );
    } catch (error) {
      log_error(`Error running preload hook: ${error.message}`, { error });
      reject(error);
    }
  });
}

// TODO: Move this function to a more generic place,
//  as it can be used by other components that want to run preload hooks
//  and add test coverage for it
export async function executePreloadHooks({
  preloadHooks,
  entry,
}: {
  preloadHooks: PreloadHookConfig[];
  entry: ZappEntry;
}): Promise<ZappEntry | null> {
  if (!preloadHooks?.length) {
    return entry;
  }

  const sortedHooks = [...preloadHooks].sort(
    (a, b) => (a.weight || 0) - (b.weight || 0)
  );

  const hookNames = sortedHooks.map((hook) => hook.identifier).join(", ");

  log_debug(
    `Preload hook sequence: ${hookNames}, entry: ${entry.id} - ${entry.title}`
  );

  let payload: any = entry;

  let needsAbort = false;
  const plugins = appStore.get("plugins");

  for (const hookConfig of sortedHooks) {
    const plugin = findPluginByIdentifier(hookConfig.identifier, plugins, true);

    if (!plugin?.module) {
      log_debug(
        `Preload hook plugin not found: ${hookConfig.identifier}, skipping`
      );

      continue;
    }

    const { module: hookModule } = plugin;

    if (hookModule.skipHook?.(payload)) {
      log_debug(`Skipping hook: ${hookConfig.identifier}`);

      continue;
    }

    if (hookModule.runInBackground) {
      log_debug(
        `Running background hook: ${hookConfig.identifier}, entry: ${payload?.id} - ${payload?.title}`
      );

      const result = await runHookWithCallback(
        (item, callback, abortCallback) =>
          hookModule
            .runInBackground(item, callback, hookConfig, abortCallback)
            ?.catch?.((error: Error) => {
              log_error(
                `Error running background preload hook: ${hookConfig.identifier}, error: ${error.message}`,
                { error }
              );

              callback({ success: false, payload: item, error });
            }),
        payload
      );

      payload = result.payload;
      needsAbort = result.aborted;
    }

    if (needsAbort) {
      log_debug(
        `Preload hook requested abort: ${hookConfig.identifier}, stopping chain`
      );

      break;
    }
  }

  if (needsAbort) {
    return null;
  }

  return payload;
}
