/**
 * ═══════════════════════════════════════════════════════════
 * 📡 AGE OS · HLDP Bus 模块间通信总线
 * ═══════════════════════════════════════════════════════════
 *
 * 编号: ZY-TASK-007 · S5 Agent系统级
 * 签发: 铸渊 · ICE-GL-ZY001
 * 版权: 国作登字-2026-A-00037559
 *
 * HLDP = HoloLake Distributed Protocol
 * 光湖分布式通信协议 · 模块间唯一通信通道
 *
 * 消息类型:
 *   heartbeat  — 心跳
 *   command    — 指令（铸渊→模块）
 *   query      — 查询
 *   response   — 响应
 *   event      — 事件
 *   broadcast  — 广播（铸渊→所有模块）
 *   alert      — 报警（模块→铸渊）
 *   data       — 数据传输
 */

'use strict';

const { v4: uuidv4 } = require('uuid');

// ─── 消息默认过期时间 ───
const DEFAULT_TTL_MS = 300000; // 5分钟

class HLDPBus {
  /**
   * @param {Object} options
   * @param {Object} [options.db]       - 数据库连接
   * @param {Object} [options.registry] - ModuleRegistry实例
   */
  constructor(options = {}) {
    this.db = options.db || null;
    this.registry = options.registry || null;

    // ─── 消息队列（内存） ───
    this._queues = new Map();  // moduleId → [messages]
    this._handlers = new Map(); // msgType → [handler]
    this._maxQueueSize = 1000; // 每个模块最多1000条待处理消息

    // ─── 广播订阅 ───
    this._subscribers = new Map(); // topic → Set(moduleId)

    // ─── 统计 ───
    this.stats = {
      totalSent: 0,
      totalDelivered: 0,
      totalFailed: 0,
      totalBroadcast: 0
    };
  }

  // ═══════════════════════════════════════════════════════════
  // 发送消息
  // ═══════════════════════════════════════════════════════════

  /**
   * 发送消息到指定模块
   * @param {string} fromModule - 发送方模块ID
   * @param {string} toModule   - 接收方模块ID
   * @param {string} msgType    - 消息类型
   * @param {Object} payload    - 消息体
   * @returns {Object} 消息对象
   */
  async send(fromModule, toModule, msgType, payload = {}) {
    const message = {
      messageId: uuidv4(),
      from: fromModule,
      to: toModule,
      type: msgType,
      payload,
      status: 'pending',
      createdAt: new Date(),
      expiresAt: new Date(Date.now() + DEFAULT_TTL_MS)
    };

    // 入队
    if (!this._queues.has(toModule)) {
      this._queues.set(toModule, []);
    }
    const queue = this._queues.get(toModule);

    // 队列大小限制：丢弃最旧的消息
    if (queue.length >= this._maxQueueSize) {
      queue.shift();
      this.stats.totalFailed++;
    }

    queue.push(message);

    // 持久化
    await this._persistMessage(message);

    // 尝试即时投递
    await this._tryDeliver(toModule, message);

    this.stats.totalSent++;
    return message;
  }

  /**
   * 广播消息到所有模块
   * @param {string} fromModule - 发送方
   * @param {string} msgType    - 消息类型
   * @param {Object} payload    - 消息体
   * @param {string} [topic]    - 广播主题（为空则广播给所有）
   */
  async broadcast(fromModule, msgType, payload = {}, topic = null) {
    const targets = topic
      ? Array.from(this._subscribers.get(topic) || [])
      : (this.registry ? this.registry.getAll().map(m => m.moduleId) : []);

    const messages = [];
    for (const targetId of targets) {
      if (targetId === fromModule) continue; // 不广播给自己
      const msg = await this.send(fromModule, targetId, msgType, {
        ...payload,
        _broadcast: true,
        _topic: topic
      });
      messages.push(msg);
    }

    this.stats.totalBroadcast++;
    return { count: messages.length, messageIds: messages.map(m => m.messageId) };
  }

  // ═══════════════════════════════════════════════════════════
  // 接收消息
  // ═══════════════════════════════════════════════════════════

  /**
   * 拉取模块的待处理消息
   * @param {string} moduleId - 模块ID
   * @param {number} [limit=10] - 最多拉取条数
   */
  pull(moduleId, limit = 10) {
    const queue = this._queues.get(moduleId) || [];
    const now = Date.now();

    // 过滤已过期的消息
    const valid = queue.filter(msg =>
      msg.status === 'pending' && msg.expiresAt.getTime() > now
    );

    const messages = valid.slice(0, limit);

    // 标记为已投递
    for (const msg of messages) {
      msg.status = 'delivered';
      msg.deliveredAt = new Date();
    }

    return messages;
  }

  /**
   * 确认消息已处理
   */
  async ack(messageId) {
    for (const [, queue] of this._queues) {
      const msg = queue.find(m => m.messageId === messageId);
      if (msg) {
        msg.status = 'processed';
        msg.processedAt = new Date();
        this.stats.totalDelivered++;

        // 更新DB
        if (this.db) {
          await this.db.query(
            `UPDATE hldp_messages SET status = 'processed', processed_at = NOW() WHERE message_id = $1`,
            [messageId]
          ).catch(() => {});
        }
        return true;
      }
    }
    return false;
  }

  // ═══════════════════════════════════════════════════════════
  // 消息处理器
  // ═══════════════════════════════════════════════════════════

  /**
   * 注册消息处理器
   * @param {string} msgType - 消息类型
   * @param {Function} handler - 处理函数 (message) => Promise<result>
   */
  onMessage(msgType, handler) {
    if (!this._handlers.has(msgType)) {
      this._handlers.set(msgType, []);
    }
    this._handlers.get(msgType).push(handler);
    return this;
  }

  /**
   * 订阅广播主题
   * @param {string} moduleId - 模块ID
   * @param {string} topic    - 主题
   */
  subscribe(moduleId, topic) {
    if (!this._subscribers.has(topic)) {
      this._subscribers.set(topic, new Set());
    }
    this._subscribers.get(topic).add(moduleId);
    return this;
  }

  /**
   * 取消订阅
   */
  unsubscribe(moduleId, topic) {
    const subs = this._subscribers.get(topic);
    if (subs) subs.delete(moduleId);
    return this;
  }

  // ═══════════════════════════════════════════════════════════
  // 内部方法
  // ═══════════════════════════════════════════════════════════

  /**
   * 尝试即时投递
   */
  async _tryDeliver(toModule, message) {
    const handlers = this._handlers.get(message.type) || [];
    for (const handler of handlers) {
      try {
        await handler(message);
      } catch (err) {
        console.warn(`[HLDP] 消息处理异常 [${message.type}]: ${err.message}`);
      }
    }
  }

  /**
   * 持久化消息到数据库
   */
  async _persistMessage(message) {
    if (!this.db) return;

    try {
      await this.db.query(
        `INSERT INTO hldp_messages (message_id, from_module, to_module, msg_type, payload, status, created_at, expires_at)
         VALUES ($1, $2, $3, $4, $5, $6, $7, $8)`,
        [
          message.messageId, message.from, message.to,
          message.type, JSON.stringify(message.payload),
          message.status, message.createdAt, message.expiresAt
        ]
      );
    } catch (err) {
      console.warn(`[HLDP] 消息持久化失败: ${err.message}`);
    }
  }

  /**
   * 清理过期消息
   */
  cleanup() {
    const now = Date.now();
    let cleaned = 0;

    for (const [moduleId, queue] of this._queues) {
      const before = queue.length;
      const filtered = queue.filter(msg =>
        msg.status !== 'processed' && msg.expiresAt.getTime() > now
      );
      this._queues.set(moduleId, filtered);
      cleaned += (before - filtered.length);
    }

    return cleaned;
  }

  /**
   * 获取总线统计信息
   */
  getStats() {
    let pendingMessages = 0;
    for (const [, queue] of this._queues) {
      pendingMessages += queue.filter(m => m.status === 'pending').length;
    }

    return {
      ...this.stats,
      pendingMessages,
      queueCount: this._queues.size,
      subscriberTopics: this._subscribers.size,
      timestamp: new Date().toISOString()
    };
  }
}

module.exports = HLDPBus;
