import {
  ConsoleTransport,
  FetchTransport,
  getWebInstrumentations,
  initializeFaro,
} from '@grafana/faro-web-sdk';
import {
  FaroTraceExporter,
  TracingInstrumentation,
} from '@grafana/faro-web-tracing';
import { context, trace } from '@opentelemetry/api';
import { getWebAutoInstrumentations } from '@opentelemetry/auto-instrumentations-web';
import { ZoneContextManager } from '@opentelemetry/context-zone';
import { W3CTraceContextPropagator } from '@opentelemetry/core';
import { registerInstrumentations } from '@opentelemetry/instrumentation';
import { Resource } from '@opentelemetry/resources';
import {
  BatchSpanProcessor,
  ConsoleSpanExporter,
  SimpleSpanProcessor,
  WebTracerProvider,
} from '@opentelemetry/sdk-trace-web';
import {
  ATTR_SERVICE_NAME,
  ATTR_SERVICE_VERSION,
} from '@opentelemetry/semantic-conventions';
import { environment } from '../../../environments/environment';
import { FaroMetaAttributesSpanProcessor } from './external/faro-meta-attributes-span-processor';
import { FaroUserActionSpanProcessor } from './external/faro-user-action-span-processor';

const VERSION = '1.0.0';

export function faroInitializer(): Function {
  return async () => {
    const faro = initializeFaro({
      instrumentations: [
        ...getWebInstrumentations({
          captureConsole: true,
          captureConsoleDisabledLevels: [],
        }),
        new TracingInstrumentation(),
      ],
      transports: [
        new FetchTransport({
          url: environment.telemetry.otlpEndpoint,
          apiKey: environment.telemetry.collectorSecret,
        }),
        new ConsoleTransport(),
      ],
      trackResources: true,
      trackUserActionsPreview: true,
      app: {
        name: environment.telemetry.serviceName,
        version: VERSION,
        namespace: 'avicenna',
      },
    });

    const resource = Resource.default().merge(
      new Resource({
        [ATTR_SERVICE_NAME]: environment.telemetry.serviceName,
        [ATTR_SERVICE_VERSION]: VERSION,
      })
    );

    const provider = new WebTracerProvider({
      resource,
      spanProcessors: [
        new SimpleSpanProcessor(new ConsoleSpanExporter()),
        new FaroUserActionSpanProcessor(
          new FaroMetaAttributesSpanProcessor(
            new BatchSpanProcessor(new FaroTraceExporter({ ...faro })),
            {
              add: () => {},
              remove: () => {},
              addListener: () => {},
              removeListener: () => {},
              value: {
                session: {
                  id: 'session-id',
                },
                user: {
                  email: 'email',
                  id: 'id',
                  username: 'user-short-name',
                  fullName: 'user-full-name',
                  roles: 'admin, editor,viewer',
                  hash: 'hash',
                },
              },
            }
          )
        ),
      ],
    });

    provider.register({
      propagator: new W3CTraceContextPropagator(),
      contextManager: new ZoneContextManager(),
    });

    const ignoreUrls = [environment.telemetry.otlpEndpoint];

    registerInstrumentations({
      instrumentations: [
        getWebAutoInstrumentations({
          // not needed to add the following, but it better shows the intention
          '@opentelemetry/instrumentation-document-load': {},
          '@opentelemetry/instrumentation-user-interaction': {},
          '@opentelemetry/instrumentation-fetch': {
            ignoreUrls,
          },
          '@opentelemetry/instrumentation-xml-http-request': {
            ignoreUrls,
          },
        }),
      ],
    });

    faro.api.initOTEL(trace, context);
  };
}
