/**
 * AI Task Registry
 *
 * Simple registry pattern for AI tasks. Each task has:
 * - id: Unique identifier
 * - run: Async function that executes the task
 *
 * This allows adding new AI capabilities without modifying core code.
 */

const { createNameValidationTask, TASK_ID: NAME_TASK_ID } = require('./nameValidationTask');
const { createDescriptionValidationTask, TASK_ID: DESC_TASK_ID } = require('./descriptionValidationTask');
const { createSanityCheckTask, TASK_ID: SANITY_TASK_ID } = require('./sanityCheckTask');

/**
 * Task IDs - frozen constants for type safety
 */
const TASK_IDS = Object.freeze({
  // Inline validation (triggered on field blur)
  VALIDATE_NAME: NAME_TASK_ID,
  VALIDATE_DESCRIPTION: DESC_TASK_ID,

  // Batch operations (triggered on user action)
  SANITY_CHECK: SANITY_TASK_ID
});

/**
 * Task Registry
 */
class TaskRegistry {
  constructor() {
    this.tasks = new Map();
  }

  /**
   * Register a task
   * @param {Object} task
   * @param {string} task.id - Unique task identifier
   * @param {Function} task.run - Async function: (payload) => result
   * @param {string} [task.description] - Human-readable description
   */
  register(task) {
    if (!task?.id) {
      throw new Error('Task must have an id');
    }
    if (typeof task.run !== 'function') {
      throw new Error(`Task ${task.id} must have a run function`);
    }
    if (this.tasks.has(task.id)) {
      throw new Error(`Task ${task.id} is already registered`);
    }

    this.tasks.set(task.id, task);
    return this;
  }

  /**
   * Get a task by ID
   * @param {string} taskId
   * @returns {Object|null}
   */
  get(taskId) {
    return this.tasks.get(taskId) || null;
  }

  /**
   * Check if a task exists
   * @param {string} taskId
   * @returns {boolean}
   */
  has(taskId) {
    return this.tasks.has(taskId);
  }

  /**
   * Run a task by ID
   * @param {string} taskId
   * @param {Object} payload - Task-specific input
   * @returns {Promise<Object>} Task result
   */
  async runTask(taskId, payload = {}) {
    const task = this.get(taskId);
    if (!task) {
      throw new Error(`Unknown task: ${taskId}`);
    }

    try {
      const result = await task.run(payload);
      return {
        success: true,
        taskId,
        ...result
      };
    } catch (error) {
      return {
        success: false,
        taskId,
        error: error.message,
        code: error.code
      };
    }
  }

  /**
   * List all registered task IDs
   * @returns {string[]}
   */
  list() {
    return Array.from(this.tasks.keys());
  }

  /**
   * Get count of registered tasks
   * @returns {number}
   */
  size() {
    return this.tasks.size;
  }
}

// Singleton instance
let registry = null;

/**
 * Get or create the task registry
 * @returns {TaskRegistry}
 */
function getRegistry() {
  if (!registry) {
    registry = new TaskRegistry();
  }
  return registry;
}

/**
 * Reset the registry (mainly for testing)
 */
function resetRegistry() {
  registry = null;
}

/**
 * Register all validation tasks with the registry
 * Call this during initialization after the registry is created
 *
 * @param {Object} [logger] - Optional logger
 */
function registerAllTasks(logger = console) {
  const reg = getRegistry();

  // Register name validation
  if (!reg.has(TASK_IDS.VALIDATE_NAME)) {
    reg.register(createNameValidationTask());
    logger.info(`[Tasks] Registered: ${TASK_IDS.VALIDATE_NAME}`);
  }

  // Register description validation
  if (!reg.has(TASK_IDS.VALIDATE_DESCRIPTION)) {
    reg.register(createDescriptionValidationTask());
    logger.info(`[Tasks] Registered: ${TASK_IDS.VALIDATE_DESCRIPTION}`);
  }

  // Register sanity check
  if (!reg.has(TASK_IDS.SANITY_CHECK)) {
    reg.register(createSanityCheckTask());
    logger.info(`[Tasks] Registered: ${TASK_IDS.SANITY_CHECK}`);
  }

  return reg;
}

module.exports = {
  // Constants
  TASK_IDS,

  // Registry
  TaskRegistry,
  getRegistry,
  resetRegistry,
  registerAllTasks,

  // Task factories (for custom registration)
  createNameValidationTask,
  createDescriptionValidationTask,
  createSanityCheckTask
};
