import {
  EnvironmentInjector,
  inject,
  runInInjectionContext
} from '@angular/core';
import type { ElectronApi } from '../../core/platform/electron/electron-api.models';
import { PerfDiagnosticsCollector, publishRendererDiagnosticsSample } from './diagnostics.collector';
import type { PerfDiagEntry, PerfDiagReporter } from './diagnostics.models';

const SAMPLE_INTERVAL_MS = 10_000;

let started = false;
let sampleTimer: ReturnType<typeof setInterval> | null = null;

export async function bootstrapPerfDiagnostics(
  api: ElectronApi,
  injector: EnvironmentInjector
): Promise<void> {
  const reportSample = api.reportPerfDiagSample;

  if (started || !api.isPerfDiagEnabled || !reportSample) {
    return;
  }

  let enabled = false;

  try {
    enabled = await api.isPerfDiagEnabled();
  } catch {
    return;
  }

  if (!enabled) {
    return;
  }

  started = true;

  const reporter: PerfDiagReporter = {
    report: (entry: PerfDiagEntry) => reportSample(entry)
  };
  const runSample = (): void => {
    void runInInjectionContext(injector, async () => {
      try {
        const collector = inject(PerfDiagnosticsCollector);

        await publishRendererDiagnosticsSample(reporter, collector);
      } catch {
        stopPerfDiagnosticsSampling();
      }
    });
  };

  scheduleSample(runSample);
  sampleTimer = setInterval(() => scheduleSample(runSample), SAMPLE_INTERVAL_MS);

  window.addEventListener('error', () => {
    void reporter.report({
      collectedAt: Date.now(),
      source: 'renderer',
      type: 'crash',
      payload: { scope: 'window-error' }
    });
  });

  window.addEventListener('unhandledrejection', () => {
    void reporter.report({
      collectedAt: Date.now(),
      source: 'renderer',
      type: 'crash',
      payload: { scope: 'unhandled-rejection' }
    });
  });
}

function scheduleSample(runSample: () => void): void {
  const idle = (globalThis as {
    requestIdleCallback?: (handler: () => void, options?: { timeout: number }) => number;
  }).requestIdleCallback;

  if (idle) {
    idle(() => runSample(), { timeout: SAMPLE_INTERVAL_MS });
    return;
  }

  setTimeout(runSample, 0);
}

function stopPerfDiagnosticsSampling(): void {
  if (sampleTimer) {
    clearInterval(sampleTimer);
    sampleTimer = null;
  }

  started = false;
}
