import type { RuntimeBreakpoint, RuntimeSourceMapIndex } from "../controller/index.js";
import type { OlpProjectModel } from "../olp/index.js";
import type { RuntimeTraceEvent } from "../controller/index.js";

export interface WorkbenchTreeNode {
  id: string;
  label: string;
  kind: "station" | "robot" | "tool" | "frame" | "target" | "path" | "operation" | "program" | "report";
  children?: WorkbenchTreeNode[];
}

export interface TeachPendantState {
  tcp?: number[];
  joints?: number[];
  mode: "manual" | "auto" | "step";
  controllerState: string;
}

export interface DebugPanelState {
  currentLine?: number;
  variables: Record<string, unknown>;
  watches: Record<string, unknown>;
  breakpoints: RuntimeBreakpoint[];
  trace: RuntimeTraceEvent[];
}

export interface WorkbenchAction {
  id: string;
  label: string;
  target: "post" | "report" | "delivery";
  enabled: boolean;
}

export interface WorkbenchState {
  tree: WorkbenchTreeNode[];
  editor: {
    activeProgramId?: string;
    text: string;
  };
  pendant: TeachPendantState;
  debug: DebugPanelState;
  io: {
    values: Record<string, unknown>;
    waiting?: string;
  };
  alarms: Array<{ id: string; message: string; severity: string }>;
  actions: WorkbenchAction[];
}

export function buildWorkbenchState(input: {
  project: OlpProjectModel;
  controllerState?: string;
  activeProgramId?: string;
  variables?: Record<string, unknown>;
  watches?: string[];
  breakpoints?: RuntimeBreakpoint[];
  trace?: RuntimeTraceEvent[];
  io?: Record<string, unknown>;
  waiting?: string;
  alarms?: Array<{ id: string; message: string; severity: string }>;
  joints?: number[];
  tcp?: number[];
}): WorkbenchState {
  const activeProgram = input.project.programs.find((program) => program.id === input.activeProgramId) ?? input.project.programs[0];
  const variables = input.variables ?? {};
  const currentLine = input.trace?.at(-1)?.source?.sourceMap?.line;
  return {
    tree: buildObjectTree(input.project),
    editor: {
      ...(activeProgram ? { activeProgramId: activeProgram.id } : {}),
      text: activeProgram?.source.text ?? ""
    },
    pendant: {
      ...(input.tcp ? { tcp: [...input.tcp] } : {}),
      ...(input.joints ? { joints: [...input.joints] } : {}),
      mode: "step",
      controllerState: input.controllerState ?? "stopped"
    },
    debug: {
      ...(currentLine !== undefined ? { currentLine } : {}),
      variables,
      watches: Object.fromEntries((input.watches ?? []).map((name) => [name, variables[name]])),
      breakpoints: input.breakpoints ?? [],
      trace: input.trace ?? []
    },
    io: {
      values: input.io ?? {},
      ...(input.waiting ? { waiting: input.waiting } : {})
    },
    alarms: input.alarms ?? [],
    actions: [
      { id: "post-export", label: "Post", target: "post", enabled: input.project.operations.length > 0 },
      { id: "report-open", label: "Report", target: "report", enabled: true },
      { id: "delivery-export", label: "Delivery", target: "delivery", enabled: input.project.programs.length > 0 }
    ]
  };
}

export function buildObjectTree(project: OlpProjectModel): WorkbenchTreeNode[] {
  return [
    {
      id: project.station.id,
      label: project.station.name,
      kind: "station",
      children: [
        ...project.resources.robots.map((item): WorkbenchTreeNode => ({ id: item.id, label: item.name, kind: "robot" })),
        ...project.resources.tools.map((item): WorkbenchTreeNode => ({ id: item.id, label: item.name, kind: "tool" })),
        ...project.resources.frames.map((item): WorkbenchTreeNode => ({ id: item.id, label: item.name, kind: "frame" })),
        ...project.targets.map((item): WorkbenchTreeNode => ({ id: item.id, label: item.name, kind: "target" })),
        ...project.paths.map((item): WorkbenchTreeNode => ({ id: item.id, label: item.name, kind: "path" })),
        ...project.operations.map((item): WorkbenchTreeNode => ({ id: item.id, label: item.name, kind: "operation" })),
        ...project.programs.map((item): WorkbenchTreeNode => ({ id: item.id, label: item.name, kind: "program" })),
        ...project.reports.map((item): WorkbenchTreeNode => ({ id: item.id, label: item.name, kind: "report" }))
      ]
    }
  ];
}

export function locateCrossSource(index: RuntimeSourceMapIndex, input: {
  pathId?: string;
  pointId?: string;
  operationId?: string;
  file?: string;
  line?: number;
}) {
  if (input.pathId && input.pointId) {
    return index.locatePathPoint(input.pathId, input.pointId);
  }
  if (input.operationId) {
    return index.locateOperation(input.operationId);
  }
  if (input.line !== undefined || input.file) {
    return index.locateSource({
      ...(input.file ? { file: input.file } : {}),
      ...(input.line !== undefined ? { line: input.line } : {})
    });
  }
  return undefined;
}
