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

/**
 * AST node for pattern matching statements
 * Represents: isMember(user, *group) { ... } limit 5
 */
export class PatternMatchNode extends BaseNode {
  constructor(location = null) {
    super('PatternMatch', location);
    this.predicate = null; // PredicateNode
    this.body = null; // EvidenceBodyNode
    this.limit = null;
    this.withClause = null; // WithClauseNode
    this.negated = false;
  }

  /**
   * Set the predicate for this pattern match
   * @param {PredicateNode} predicate - Predicate to set
   */
  setPredicate(predicate) {
    this.predicate = predicate;
    this.addChild(predicate);
  }

  /**
   * Set the body of the pattern match
   * @param {EvidenceBodyNode} body - Evidence body
   */
  setBody(body) {
    this.body = body;
    this.addChild(body);
  }

  /**
   * Set the limit for this pattern match
   * @param {number} limit - Limit value
   */
  setLimit(limit) {
    this.limit = limit;
  }

  /**
   * Set the with clause for this pattern match
   * @param {WithClauseNode} withClause - With clause
   */
  setWithClause(withClause) {
    this.withClause = withClause;
    this.addChild(withClause);
  }

  /**
   * Set whether this pattern match is negated
   * @param {boolean} negated - Whether pattern match is negated
   */
  setNegated(negated) {
    this.negated = negated;
  }

  /**
   * Check if this pattern match is negated
   * @returns {boolean} True if negated
   */
  isNegated() {
    return this.negated;
  }

  /**
   * Get the predicate name
   * @returns {string|null} Predicate name or null
   */
  getPredicateName() {
    return this.predicate ? this.predicate.name : null;
  }

  /**
   * Get the predicate arguments
   * @returns {ExpressionNode[]} Predicate arguments
   */
  getArguments() {
    return this.predicate ? this.predicate.arguments : [];
  }

  /**
   * Check if this pattern match has a limit
   * @returns {boolean} True if has limit
   */
  hasLimit() {
    return this.limit !== null;
  }

  /**
   * Check if this pattern match has a with clause
   * @returns {boolean} True if has with clause
   */
  hasWithClause() {
    return this.withClause !== null;
  }

  /**
   * Validate the pattern match
   * @returns {string[]} Array of error messages
   */
  validate() {
    const errors = [];

    // Validate predicate
    if (!this.predicate) {
      errors.push('Pattern match must have a predicate');
    } else {
      const predErrors = this.predicate.validate ? this.predicate.validate() : [];
      errors.push(...predErrors);
    }

    // Validate body
    if (this.body) {
      const bodyErrors = this.body.validate ? this.body.validate() : [];
      errors.push(...bodyErrors);
    }

    // Validate limit
    if (this.limit !== null && (typeof this.limit !== 'number' || this.limit < 0)) {
      errors.push(`Invalid limit: ${this.limit}`);
    }

    // Validate with clause
    if (this.withClause) {
      const withErrors = this.withClause.validate ? this.withClause.validate() : [];
      errors.push(...withErrors);
    }

    return errors;
  }

  toString() {
    const negStr = this.negated ? 'NOT ' : '';
    const predStr = this.predicate ? this.predicate.toString() : 'null';
    const limitStr = this.limit ? ` limit ${this.limit}` : '';
    const withStr = this.withClause ? ` ${this.withClause.toString()}` : '';
    return `PatternMatch(${negStr}${predStr}${limitStr}${withStr})`;
  }
}
