import { BaseNode } from './BaseNode.js';

/**
 * AST node for source definitions
 * Represents: source *mfa(user: User) PROVIDES Proof within 10m
 *
 * Sources are injectable object/proof references that must be
 * provided in the partial graph before authorization evaluation.
 * They always carry a PROVIDES type and an optional freshness window.
 */
export class SourceNode extends BaseNode {
  constructor(name, location = null) {
    super('Source', location);
    this.name = name;
    this.injectable = false;
    this.parameters = [];
    this.returnType = null;
    this.provides = null;
    this.within = null;
    this.cacheDirective = null;
  }

  addParameter(parameter) {
    this.parameters.push(parameter);
    this.addChild(parameter);
  }

  setReturnType(returnType) {
    this.returnType = returnType;
    this.provides = returnType;
  }

  setWithin(within) {
    this.within = within;
  }

  setCacheDirective(directive) {
    this.cacheDirective = directive;
  }

  setInjectable(value) {
    this.injectable = !!value;
  }

  getParameterNames() {
    return this.parameters.map(param => param.name);
  }

  getParameterTypes() {
    return this.parameters.map(param => param.type);
  }

  getParameter(name) {
    return this.parameters.find(param => param.name === name) || null;
  }

  getSignature() {
    const paramStr = this.parameters.map(param => `${param.name}: ${param.type}`).join(', ');
    return `${this.name}(${paramStr})`;
  }

  hasReturnType() {
    return this.returnType !== null;
  }

  validate() {
    const errors = [];

    if (!this.name || typeof this.name !== 'string') {
      errors.push(`Invalid source name: ${this.name}`);
    }

    this.parameters.forEach((param, index) => {
      const paramErrors = param.validate ? param.validate() : [];
      errors.push(...paramErrors.map(err => `Parameter ${index + 1}: ${err}`));
    });

    return errors;
  }

  toString() {
    const injectableStr = this.injectable ? '*' : '';
    const providesStr = this.returnType ? ` PROVIDES ${this.returnType}` : '';
    const withinStr = this.within ? ` within ${this.within.value}` : '';
    return `Source(${injectableStr}${this.getSignature()}${providesStr}${withinStr})`;
  }
}
