import { StepConfig, WorkflowDefinitionData, ConditionFunction, TaskStepConfig, ConditionStepConfig, ParallelStepConfig, SubWorkflowStepConfig, StepType } from '../types/config';
import { ConfigurationError } from '../errors';

export class WorkflowDefinition {
  private data: WorkflowDefinitionData;

  constructor(id: string, name?: string, description?: string) {
    if (!id) throw new ConfigurationError('Workflow definition ID is required.');
    this.data = {
      id,
      name,
      description,
      steps: {},
    };
  }

  // --- Chainable Methods for Building ---

  addStep(config: Omit<TaskStepConfig, 'type'>): this {
      this._addStepInternal({ ...config, type: StepType.TASK });
      return this;
  }

  addCondition(config: Omit<ConditionStepConfig, 'type'>): this {
      this._addStepInternal({ ...config, type: StepType.CONDITION });
      return this;
  }

  addParallel(config: Omit<ParallelStepConfig, 'type'>): this {
      // TODO: Add validation for parallel steps structure
      this._addStepInternal({ ...config, type: StepType.PARALLEL });
      return this;
  }

   addSubWorkflow(config: Omit<SubWorkflowStepConfig, 'type'>): this {
       this._addStepInternal({ ...config, type: StepType.SUB_WORKFLOW });
       return this;
   }

    // TODO: Add methods for EventTrigger, EventListener etc.

  setStartStep(stepId: string): this {
    if (!this.data.steps[stepId]) {
      throw new ConfigurationError(`Cannot set start step: Step with ID '${stepId}' does not exist in definition '${this.data.id}'.`);
    }
    this.data.startStepId = stepId;
    return this;
  }

  // --- Internal Logic ---
  private _addStepInternal(config: StepConfig): void {
      if (!config.id) throw new ConfigurationError('Step ID is required.');
      if (this.data.steps[config.id]) throw new ConfigurationError(`Step with ID '${config.id}' already exists in definition '${this.data.id}'.`);
      // TODO: Add more validation based on step type (e.g., nextStepId presence/absence)
      this.data.steps[config.id] = config;
  }

  // --- Accessors ---
  get id(): string { return this.data.id; }
  get name(): string | undefined { return this.data.name; }
  get description(): string | undefined { return this.data.description; }
  get startStepId(): string | undefined { return this.data.startStepId; }

  getStep(stepId: string): StepConfig | undefined {
    return this.data.steps[stepId];
  }

  getSteps(): Readonly<Record<string, StepConfig>> {
      return this.data.steps;
  }

  // Get the raw data for persistence or inspection
  getData(): Readonly<WorkflowDefinitionData> {
      return this.data;
  }

  // TODO: Add a validate() method similar to Root
  validate(): boolean {
      if (!this.data.startStepId) {
          console.error(`[Validation Error] Workflow '${this.id}': Start step not set.`);
          return false;
      }
      // TODO: Check for unreachable steps, cycles (if not allowed), valid nextStepId refs etc.
      return true;
  }
}