import { Config, Module } from "@clarity-types/core";
import { Constant } from "@clarity-types/data";
import * as queue from "@src/queue";
import * as core from "@src/core";
import measure from "@src/core/measure";
import * as task from "@src/core/task";
import version from "@src/core/version";
import * as data from "@src/data";
import { start as diagStart, stop as diagStop } from "@src/diagnostic";
import { start as interStart, stop as interStop } from "@src/interaction";
import { start as layoutStart, stop as layoutStop } from "@src/layout";
import { start as perfStart, stop as perfStop } from "@src/performance";
import { start as dynStart, stop as dynStop } from "@src/core/dynamic";
export { version };
export { consent, consentv2, event, identify, set, upgrade, metadata, signal, maxMetric, dlog } from "@src/data";
export { queue } from "@src/data/upload";
export { register } from "@src/core/dynamic";
export { schedule } from "@src/core/task";
export { time } from "@src/core/time";
export { hashText } from "@src/layout";
export { measure };
const modules: Module[] = [
  { start: diagStart, stop: diagStop },
  { start: layoutStart, stop: layoutStop },
  { start: interStart, stop: interStop },
  { start: perfStart, stop: perfStop },
  { start: dynStart, stop: dynStop },
];

export function start(config: Config = null): void {
  // Check that browser supports required APIs and we do not attempt to start Clarity multiple times
  if (core.check()) {
    core.config(config);
    core.start();
    data.start();
    modules.forEach(x => measure(x.start)());

    // If it's an internal call to start, without explicit configuration,
    // re-process any newly accumulated items in the queue
    if (config === null) { queue.process(); }
  }
}

// By default Clarity is asynchronous and will yield by looking for requestIdleCallback.
// However, there can still be situations with single page apps where a user action can result
// in the whole DOM being destroyed and reconstructed. While Clarity will perform favorably out of the box,
// we do allow external clients to manually pause Clarity for that short burst of time and minimize
// performance impact even further. For reference, we are talking single digit milliseconds optimization here, not seconds.
export function pause(): void {
  if (core.active()) {
    data.event(Constant.Clarity, Constant.Pause);
    task.pause();
  }
}

// This is how external clients can get out of pause state, and resume Clarity to continue monitoring the page
export function resume(): void {
  if (core.active()) {
    task.resume();
    data.event(Constant.Clarity, Constant.Resume);
  }
}

export function stop(): void {
  if (core.active()) {
    // Stop modules in the reverse order of their initialization and start queuing up items again
    modules.slice().reverse().forEach(x => measure(x.stop)());
    data.stop();
    core.stop();
    queue.setup();
  }
}