import type {
  JointTarget,
  MoveCRequest,
  MoveJRequest,
  MoveLRequest,
  MotionDiagnostic,
  MotionSourceMap,
  PathEventRequest,
  PathPlanRequest,
  Pose,
  PoseTarget,
  SpeedSpec,
  ZoneSpec
} from "../../kdl/types.js";

export type MotionKind = "MOVEJ" | "MOVEL" | "MOVEC";

export interface MotionInstruction {
  id?: string;
  kind: MotionKind;
  target?: JointTarget | PoseTarget;
  via?: PoseTarget;
  speed: SpeedSpec;
  zone: ZoneSpec;
  tool?: Pose;
  frame?: Pose;
  sourceMap?: MotionSourceMap;
  pathId?: string;
  pointId?: string;
  source?: Record<string, unknown>;
}

export type CompiledMotionRequest = MoveJRequest | MoveLRequest | MoveCRequest;

export interface PathEventInstruction {
  id?: string;
  timing: PathEventRequest["timing"];
  pointId: string;
  distance?: number;
  kind: string;
  sourceMap?: MotionSourceMap;
  data?: Record<string, unknown>;
}

export interface CompiledPath {
  pathId: string;
  request: PathPlanRequest;
  motions: MotionInstruction[];
  events: PathEventInstruction[];
}

export interface RunPathInstruction {
  kind: "RUN_PATH";
  pathId: string;
  sourceMap?: MotionSourceMap;
}

export interface OperationActionInstruction {
  kind: "ACTION";
  actionKind: "start_action" | "end_action";
  operationId: string;
  statement: string;
  tokens?: unknown[];
  sourceMap?: MotionSourceMap;
}

export interface CompiledOperation {
  operationId: string;
  kind: string;
  pathId: string;
  process: Record<string, unknown>;
  startActions: OperationActionInstruction[];
  endActions: OperationActionInstruction[];
}

export interface RunOperationInstruction {
  kind: "RUN_OPERATION";
  operationId: string;
  sourceMap?: MotionSourceMap;
}

export type OperationExecutionStep =
  | OperationActionInstruction
  | RunPathInstruction;

export type IoDomain = "di" | "do" | "ai" | "ao" | "gi" | "go" | "ri" | "ro" | "alias";

export interface IoReference {
  domain: IoDomain;
  index?: number;
  alias?: string;
  raw: string;
}

export interface IoWriteInstruction {
  kind: "IO_WRITE";
  target: IoReference;
  value: boolean | number | string;
  sourceMap?: MotionSourceMap;
}

export interface WaitInstruction {
  kind: "WAIT";
  condition: string;
  timeout?: number;
  onTimeout?: {
    kind: "alarm" | "call";
    value: string;
  };
  sourceMap?: MotionSourceMap;
}

export interface PulseInstruction {
  kind: "PULSE";
  target: IoReference;
  duration: number;
  trace: Array<{
    time: number;
    action: "set" | "reset";
    target: IoReference;
    value: boolean;
  }>;
  sourceMap?: MotionSourceMap;
}

export type IoFlowInstruction = IoWriteInstruction | WaitInstruction | PulseInstruction;

export interface ControlExpression {
  text: string;
  tokens?: unknown[];
  sourceMap?: MotionSourceMap;
}

export interface RawProcedureStatement {
  kind: "RAW_STATEMENT";
  text: string;
  tokens?: unknown[];
  sourceMap?: MotionSourceMap;
}

export interface IfBranch {
  branchKind: "if" | "elseif" | "else";
  condition?: ControlExpression;
  body: ProcedureFlowInstruction[];
  sourceMap?: MotionSourceMap;
}

export interface IfInstruction {
  kind: "IF";
  branches: IfBranch[];
  sourceMap?: MotionSourceMap;
}

export interface WhileInstruction {
  kind: "WHILE";
  condition: ControlExpression;
  body: ProcedureFlowInstruction[];
  sourceMap?: MotionSourceMap;
}

export interface ForInstruction {
  kind: "FOR";
  iterator: string;
  from: ControlExpression;
  to: ControlExpression;
  step?: ControlExpression;
  body: ProcedureFlowInstruction[];
  sourceMap?: MotionSourceMap;
}

export interface SwitchCaseInstruction {
  caseKind: "case" | "default";
  value?: string | number | boolean;
  raw?: string;
  body: ProcedureFlowInstruction[];
  sourceMap?: MotionSourceMap;
}

export interface SwitchInstruction {
  kind: "SWITCH";
  expression: ControlExpression;
  cases: SwitchCaseInstruction[];
  sourceMap?: MotionSourceMap;
}

export interface BreakInstruction {
  kind: "BREAK";
  sourceMap?: MotionSourceMap;
}

export interface ContinueInstruction {
  kind: "CONTINUE";
  sourceMap?: MotionSourceMap;
}

export interface LabelInstruction {
  kind: "LABEL";
  name: string;
  scopePath: string[];
  sourceMap?: MotionSourceMap;
}

export interface JumpInstruction {
  kind: "JUMP";
  label: string;
  scopePath: string[];
  sourceMap?: MotionSourceMap;
}

export type ControlFlowInstruction =
  | IfInstruction
  | WhileInstruction
  | ForInstruction
  | SwitchInstruction
  | BreakInstruction
  | ContinueInstruction
  | LabelInstruction
  | JumpInstruction;

export type ProcedureFlowInstruction = ControlFlowInstruction | RawProcedureStatement;

export type RoutineParameterDirection = "in" | "out" | "inout";

export interface RoutineParameter {
  name: string;
  typeName: string;
  direction: RoutineParameterDirection;
  sourceMap?: MotionSourceMap;
}

export interface ProcedureSignature {
  kind: "PROC_SIGNATURE";
  name: string;
  parameters: RoutineParameter[];
  sourceMap?: MotionSourceMap;
}

export interface FunctionSignature {
  kind: "FUNC_SIGNATURE";
  name: string;
  returnType: string;
  parameters: RoutineParameter[];
  sourceMap?: MotionSourceMap;
}

export interface CallInstruction {
  kind: "CALL";
  target: string;
  args: ControlExpression[];
  sourceMap?: MotionSourceMap;
}

export interface ReturnInstruction {
  kind: "RETURN";
  value?: ControlExpression;
  sourceMap?: MotionSourceMap;
}

export interface ProcFunctionAnalysis {
  procedures: ProcedureSignature[];
  functions: FunctionSignature[];
  calls: CallInstruction[];
  returns: ReturnInstruction[];
  diagnostics: MotionDiagnostic[];
}

export interface AlarmInstruction {
  kind: "ALARM";
  alarmId: string;
  message?: string;
  severity?: string;
  sourceMap?: MotionSourceMap;
}

export interface RaiseInstruction {
  kind: "RAISE";
  alarmId: string;
  sourceMap?: MotionSourceMap;
}

export interface CatchInstruction {
  alarmId?: string;
  body: ExceptionFlowInstruction[];
  sourceMap?: MotionSourceMap;
}

export interface FinallyInstruction {
  body: ExceptionFlowInstruction[];
  sourceMap?: MotionSourceMap;
}

export interface TryInstruction {
  kind: "TRY";
  body: ExceptionFlowInstruction[];
  catches: CatchInstruction[];
  finally?: FinallyInstruction;
  sourceMap?: MotionSourceMap;
}

export interface UnsupportedRuntimeInstruction {
  kind: "UNSUPPORTED_RUNTIME";
  feature: "trap" | "interrupt" | "task";
  message: string;
  sourceMap?: MotionSourceMap;
}

export type ExceptionInstruction =
  | AlarmInstruction
  | RaiseInstruction
  | TryInstruction
  | UnsupportedRuntimeInstruction;

export type ExceptionFlowInstruction = ExceptionInstruction | RawProcedureStatement;

export type SemanticSymbolKind =
  | "data"
  | "target"
  | "path"
  | "operation"
  | "procedure"
  | "function"
  | "raw";

export interface SemanticSymbol {
  kind: SemanticSymbolKind;
  name: string;
  typeName?: string;
  sourceMap?: MotionSourceMap;
}

export interface SemanticSourceMapEntry {
  kind: string;
  id: string;
  sourceMap: MotionSourceMap;
  pathId?: string;
  pointId?: string;
  operationId?: string;
  procedureId?: string;
}

export interface ExecutableBranch {
  branchKind: "if" | "elseif" | "else";
  condition?: ControlExpression;
  body: ExecutableInstruction[];
  sourceMap?: MotionSourceMap;
}

export interface ExecutableIfInstruction {
  kind: "EXEC_IF";
  branches: ExecutableBranch[];
  sourceMap?: MotionSourceMap;
}

export interface ExecutableWhileInstruction {
  kind: "EXEC_WHILE";
  condition: ControlExpression;
  body: ExecutableInstruction[];
  sourceMap?: MotionSourceMap;
}

export interface ExecutableForInstruction {
  kind: "EXEC_FOR";
  iterator: string;
  from: ControlExpression;
  to: ControlExpression;
  step?: ControlExpression;
  body: ExecutableInstruction[];
  sourceMap?: MotionSourceMap;
}

export interface ExecutableSwitchCase {
  caseKind: "case" | "default";
  value?: string | number | boolean;
  raw?: string;
  body: ExecutableInstruction[];
  sourceMap?: MotionSourceMap;
}

export interface ExecutableSwitchInstruction {
  kind: "EXEC_SWITCH";
  expression: ControlExpression;
  cases: ExecutableSwitchCase[];
  sourceMap?: MotionSourceMap;
}

export type ExecutableControlInstruction =
  | ExecutableIfInstruction
  | ExecutableWhileInstruction
  | ExecutableForInstruction
  | ExecutableSwitchInstruction;

export type ExecutableInstruction =
  | MotionInstruction
  | IoFlowInstruction
  | RunPathInstruction
  | RunOperationInstruction
  | CallInstruction
  | ReturnInstruction
  | BreakInstruction
  | ContinueInstruction
  | AlarmInstruction
  | RaiseInstruction
  | UnsupportedRuntimeInstruction
  | ExecutableControlInstruction
  | RawProcedureStatement;

export interface ExecutableProcedure {
  name: string;
  instructions: ExecutableInstruction[];
  sourceMap?: MotionSourceMap;
}

export interface KdlBridgeRequests {
  motionRequests: CompiledMotionRequest[];
  pathRequests: PathPlanRequest[];
}

export interface SemanticProgramIr {
  moduleName: string;
  symbols: SemanticSymbol[];
  semanticChecks: string[];
  procedures: ExecutableProcedure[];
  paths: CompiledPath[];
  operations: CompiledOperation[];
  diagnostics: MotionDiagnostic[];
  sourceMap: SemanticSourceMapEntry[];
  kdlBridge: KdlBridgeRequests;
}
