import * as vscode from "vscode";
import { SIDEBAR_VIEW_ID } from "./constants";
import { Logger } from "./utils";

import { WebviewSwitcherProvider } from "./providers/webviewSwitcherProvider";
import { GlobalState, GlobalStateKey } from "./globalState";
import { InitWebviewProvider } from "./providers/InitWebviewProvider";
import { InitService } from "./services/initService";
import { LogsEventEmitter } from "./utils/logsEventEmitter";
import { CodeflashAuthProvider } from "./providers/CodeflashAuthProvider";
import { SentryLogger } from "./telemetry/sentry";
import { EventTracker } from "./telemetry/posthog";
import { getExtensionVersion } from "./utils/vscode";
import type { IdeInfo } from "./telemetry/types";
import { ConfigService } from "./services/configService";
import { POSTHOG_EVENTS } from "./telemetry/events";

let logger: Logger = new Logger("Codeflash Extension");

const addDisposable = (
  ctx: vscode.ExtensionContext,
  ...inputDisposables: vscode.Disposable[]
) => {
  ctx.subscriptions.push(...inputDisposables);
};

const provideReloadExtensionCommand = (
  context: vscode.ExtensionContext,
): vscode.Disposable => {
  const reloadExtensionCommand = vscode.commands.registerCommand(
    "codeflash.reloadExtension",
    async () => {
      // dispose all disposables
      while (context.subscriptions.length) {
        const disposable = context.subscriptions.pop();
        if (disposable) {
          try {
            await disposable.dispose();
          } catch (err) {
            logger.error("failed to dispose", err as Error);
          }
        }
      }
      // wait for the activation. Mainly to avoid the registeration of the reload command while the existing one is still being disposed which will cause multiple reload command handlers being invoked.
      setTimeout(async () => {
        logger.info("Reloading Codeflash extension...");
        await activate(context);
      }, 500);
    },
  );
  return reloadExtensionCommand;
};

const webviewSwitcherProvider = new WebviewSwitcherProvider({
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
  resolveWebviewView(_webviewView, _context, _token) {},
});

export async function activate(
  context: vscode.ExtensionContext,
): Promise<void> {
  logger.info("Activating Codeflash extension...");
  addDisposable(context, provideReloadExtensionCommand(context));

  const ideInfo: IdeInfo = {
    name: vscode.env.appName,
    extensionVersion: getExtensionVersion(),
  };
  const uniqueId = vscode.env.machineId;
  SentryLogger.setup(true, uniqueId, ideInfo);
  await EventTracker.setup(true, ideInfo);
  await EventTracker.identify(uniqueId);

  addDisposable(context, {
    dispose: () => {
      SentryLogger.shutdownSentryClient();
      EventTracker.shutdownPosthogClient();
    },
  });

  const globalState = new GlobalState(context);
  const configService = new ConfigService();

  if (!globalState.get(GlobalStateKey.IsExtensionInstalled, false)) {
    await EventTracker.capture(POSTHOG_EVENTS.EXTENSION_INSTALLED, {});
    globalState.set(GlobalStateKey.IsExtensionInstalled, true);
    // show the sidebar view on first install
    vscode.commands.executeCommand(
      "workbench.view.extension." + SIDEBAR_VIEW_ID,
    );
    // maybe here we can open a welcome page, with some getting started guide
  }
  const optimizationEventEmitter = new LogsEventEmitter(globalState); // for emitting events from the lsp server logs to the sidebar, for tracking the running optimization progress
  const codeflashAuth = new CodeflashAuthProvider(context);
  addDisposable(context, codeflashAuth);
  const showGlobalStateCommand = vscode.commands.registerCommand(
    "codeflash.dev.showGlobalState",
    async () => {
      await globalState.showGlobalStateValue();
    },
  );
  addDisposable(context, showGlobalStateCommand);

  const initService = new InitService(
    context,
    globalState,
    configService,
    optimizationEventEmitter,
  );

  const initWebviewProvider = new InitWebviewProvider(
    context.extensionUri,
    initService,
  );

  addDisposable(
    context,
    initService,
    vscode.window.registerWebviewViewProvider(
      SIDEBAR_VIEW_ID,
      webviewSwitcherProvider,
      { webviewOptions: { retainContextWhenHidden: true } },
    ),
    initWebviewProvider,
  );

  setTimeout(async () => {
    webviewSwitcherProvider.switchTo(initWebviewProvider);
    const result = await initService.initWithRetries();
    if (!result) {
      return;
    }
    logger.info("Init completed");
    const bootResult = result.bootResult!;
    webviewSwitcherProvider.switchTo(bootResult.sidebarProvider);
  }, 0);
}
