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

/**
 * AST node for fact definitions
 * Represents: fact hasRole(user: User, role: string) CACHE lazy
 */
export class FactNode extends BaseNode {
  constructor(name, location = null) {
    super('Fact', location);
    this.name = name;
    this.parameters = [];
    this.returnType = null;
    this.properties = new Map(); // transitive, symmetrical, etc.
    this.cacheDirective = null;
    this.limit = null;
  }

  /**
   * Add a parameter to the fact
   * @param {ParameterNode} parameter - Parameter to add
   */
  addParameter(parameter) {
    this.parameters.push(parameter);
    this.addChild(parameter);
  }

  /**
   * Set the return type for this fact
   * @param {string} returnType - Return type
   */
  setReturnType(returnType) {
    this.returnType = returnType;
  }

  /**
   * Set a property for this fact
   * @param {string} name - Property name
   * @param {*} value - Property value
   */
  setProperty(name, value) {
    this.properties.set(name, value);
  }

  /**
   * Get a property value
   * @param {string} name - Property name
   * @returns {*} Property value or null
   */
  getProperty(name) {
    return this.properties.get(name) || null;
  }

  /**
   * Set the cache directive for this fact
   * @param {string} directive - Cache directive ('lazy')
   */
  setCacheDirective(directive) {
    if (directive === 'eager') {
      if (!FactNode._warnedEagerCacheDirective) {
        FactNode._warnedEagerCacheDirective = true;
        console.warn('[FactNode] CACHE eager is deprecated; treating as CACHE lazy.');
      }
      this.cacheDirective = 'lazy';
      return;
    }
    this.cacheDirective = directive;
  }

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

  /**
   * Check if this fact is transitive
   * @returns {boolean} True if transitive
   */
  isTransitive() {
    return this.getProperty('transitive') === true;
  }

  /**
   * Check if this fact is symmetrical
   * @returns {boolean} True if symmetrical
   */
  isSymmetrical() {
    return this.getProperty('symmetrical') === true;
  }

  /**
   * Get the parameter names as an array
   * @returns {string[]} Array of parameter names
   */
  getParameterNames() {
    return this.parameters.map(param => param.name);
  }

  /**
   * Get the parameter types as an array
   * @returns {string[]} Array of parameter types
   */
  getParameterTypes() {
    return this.parameters.map(param => param.type);
  }

  /**
   * Find a parameter by name
   * @param {string} name - Parameter name to find
   * @returns {ParameterNode|null} Found parameter or null
   */
  getParameter(name) {
    return this.parameters.find(param => param.name === name) || null;
  }

  /**
   * Get the signature string for this fact
   * @returns {string} Fact signature
   */
  getSignature() {
    const paramStr = this.parameters.map(param => `${param.name}: ${param.type}`).join(', ');
    return `${this.name}(${paramStr})`;
  }

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

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

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

    // Validate cache directive
    if (this.cacheDirective && !['lazy'].includes(this.cacheDirective)) {
      errors.push(`Invalid cache directive: ${this.cacheDirective}`);
    }

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

    return errors;
  }

  toString() {
    const props = Array.from(this.properties.entries())
      .map(([key, value]) => `${key}: ${value}`)
      .join(', ');
    const cacheStr = this.cacheDirective ? ` CACHE ${this.cacheDirective}` : '';
    const limitStr = this.limit ? ` LIMIT ${this.limit}` : '';
    return `Fact(${this.getSignature()}${props ? `, ${props}` : ''}${cacheStr}${limitStr})`;
  }
}
