import type { CodeflashCodeLensProvider } from "../providers/CodeLensProvider";
import type { CommentThreadProvider } from "../providers/commentThreadProvider";
import type { SidebarProvider } from "../providers/SidebarProvider";
import type {
  AnalysisService,
  LspService,
  NavigationService,
  OptimizationService,
} from "../services";
import { Disposable } from "../utils/dispose";

/**
 * Step definition for onboarding progress indicator.
 * These are displayed in order during the initialization flow.
 */
export interface StepDefinition {
  id: string;
  title: string;
  shortTitle: string;
}

/**
 * All step definitions in order. Used to dynamically render the progress indicator.
 */
export const STEP_DEFINITIONS: StepDefinition[] = [
  {
    id: "environment",
    title: "Install Codeflash Python package",
    shortTitle: "Install",
  },
  {
    id: "server",
    title: "Starting Codeflash server",
    shortTitle: "Start",
  },
  {
    id: "init",
    title: "Initializing Codeflash",
    shortTitle: "Activate",
  },
];

export type BootCodeflashServerStepResult = {
  lspService: LspService;
  optimizationLspService: LspService;
  analysisService: AnalysisService;
  optimizationService: OptimizationService;
  navigationService: NavigationService;
  sidebarProvider: SidebarProvider;
  codeLensProvider: CodeflashCodeLensProvider;
  commentThreadProvider: CommentThreadProvider;
};

export type CheckEnvironmentStepResult = {
  pythonPath: string;
  codeflashVersion: string;
};

export interface CodeflashInitResult {
  userId: string | undefined;
  pyprojectPath: string | undefined;
  configSuggestions: Record<string, unknown>;
}

export type StepResult =
  | BootCodeflashServerStepResult
  | CheckEnvironmentStepResult
  | CodeflashInitResult;

export class InitStepError extends Error {
  public category?: string;
  public details?: string;
  public helperCmdText?: string;
  public helperCmd?: string;
  public icon?: string;
  public iconFill?: string;
  public vscodeActionCommand?: {
    title: string;
    command: string;
    btnText: string;
    args?: unknown[];
  };
  public installAction?: {
    btnText: string;
    command: string;
    showCommand?: boolean;
    disclaimer?: string;
  };

  constructor(message: string) {
    super(message);
    this.name = "InitStepError";
    Object.setPrototypeOf(this, new.target.prototype);
    Error.captureStackTrace?.(this, InitStepError);
  }
}

abstract class BaseStep extends Disposable {
  private title: string = "";

  get stepTitle(): string {
    return this.title;
  }

  constructor(title: string) {
    super();
    this.title = title;
  }

  abstract run(...args: unknown[]): Promise<StepResult | InitStepError>;
}

export default BaseStep;
