/**
 * DSS Notification Service
 *
 * Centralized messaging system with structured formats, error taxonomy,
 * and correlation IDs for enterprise-grade error tracking and user feedback.
 *
 * @module messaging
 */

// Event bus for pub/sub notifications
const bus = new EventTarget();

// Event name constant
export const NOTIFICATION_EVENT = 'dss-notification';

/**
 * Notification severity types
 */
export const NotificationType = {
  SUCCESS: 'success',
  ERROR: 'error',
  WARNING: 'warning',
  INFO: 'info',
};

/**
 * Error taxonomy for structured error handling
 */
export const ErrorCode = {
  // User errors (E1xxx)
  USER_INPUT_INVALID: 'E1001',
  USER_ACTION_FORBIDDEN: 'E1002',
  USER_NOT_AUTHENTICATED: 'E1003',

  // Validation errors (E2xxx)
  VALIDATION_FAILED: 'E2001',
  VALIDATION_MISSING_FIELD: 'E2002',
  VALIDATION_INVALID_FORMAT: 'E2003',

  // API errors (E3xxx)
  API_REQUEST_FAILED: 'E3001',
  API_TIMEOUT: 'E3002',
  API_UNAUTHORIZED: 'E3003',
  API_NOT_FOUND: 'E3004',
  API_SERVER_ERROR: 'E3005',

  // System errors (E4xxx)
  SYSTEM_UNEXPECTED: 'E4001',
  SYSTEM_NETWORK: 'E4002',
  SYSTEM_STORAGE: 'E4003',

  // Integration errors (E5xxx)
  FIGMA_CONNECTION_FAILED: 'E5001',
  FIGMA_INVALID_KEY: 'E5002',
  FIGMA_API_ERROR: 'E5003',

  // Success codes (S1xxx)
  SUCCESS_OPERATION: 'S1001',
  SUCCESS_CREATED: 'S1002',
  SUCCESS_UPDATED: 'S1003',
  SUCCESS_DELETED: 'S1004',
};

/**
 * Generate correlation ID for request tracking
 * @returns {string} UUID v4 correlation ID
 */
function generateCorrelationId() {
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
    const r = Math.random() * 16 | 0;
    const v = c === 'x' ? r : (r & 0x3 | 0x8);
    return v.toString(16);
  });
}

/**
 * Message queue for persistence
 */
class MessageQueue {
  constructor(maxSize = 50) {
    this.maxSize = maxSize;
    this.storageKey = 'dss_message_queue';
  }

  /**
   * Add message to queue
   * @param {Object} message - Notification message
   */
  add(message) {
    try {
      const queue = this.getAll();
      queue.unshift(message);

      // Keep only last maxSize messages
      const trimmed = queue.slice(0, this.maxSize);

      localStorage.setItem(this.storageKey, JSON.stringify(trimmed));
    } catch (error) {
      console.warn('Failed to persist message to queue:', error);
    }
  }

  /**
   * Get all messages from queue
   * @returns {Array} Array of messages
   */
  getAll() {
    try {
      const data = localStorage.getItem(this.storageKey);
      return data ? JSON.parse(data) : [];
    } catch (error) {
      console.warn('Failed to read message queue:', error);
      return [];
    }
  }

  /**
   * Clear the message queue
   */
  clear() {
    try {
      localStorage.removeItem(this.storageKey);
    } catch (error) {
      console.warn('Failed to clear message queue:', error);
    }
  }

  /**
   * Get recent errors for debugging
   * @param {number} limit - Max number of errors to return
   * @returns {Array} Recent error messages
   */
  getRecentErrors(limit = 10) {
    const queue = this.getAll();
    return queue
      .filter(msg => msg.type === NotificationType.ERROR)
      .slice(0, limit);
  }
}

// Singleton message queue
const messageQueue = new MessageQueue();

/**
 * Send a notification
 *
 * @param {Object} detail - Notification details
 * @param {string} detail.message - User-facing message
 * @param {NotificationType} [detail.type=INFO] - Notification type
 * @param {string} [detail.code] - Machine-readable error code
 * @param {Object} [detail.metadata] - Additional context for logging
 * @param {string} [detail.correlationId] - Optional correlation ID (auto-generated if not provided)
 * @param {number} [detail.duration] - Auto-dismiss duration in ms (0 = no auto-dismiss)
 *
 * @example
 * notify({
 *   message: 'Project created successfully',
 *   type: NotificationType.SUCCESS,
 *   code: ErrorCode.SUCCESS_CREATED,
 *   metadata: { projectId: 'demo-ds' }
 * });
 *
 * @example
 * notify({
 *   message: 'Failed to connect to Figma',
 *   type: NotificationType.ERROR,
 *   code: ErrorCode.FIGMA_CONNECTION_FAILED,
 *   metadata: { fileKey: 'abc123', endpoint: '/figma/file' },
 *   correlationId: 'custom-id-123'
 * });
 */
export function notify(detail) {
  const notification = {
    id: generateCorrelationId(),
    message: detail.message,
    type: detail.type || NotificationType.INFO,
    code: detail.code || null,
    metadata: detail.metadata || {},
    correlationId: detail.correlationId || generateCorrelationId(),
    timestamp: new Date().toISOString(),
    duration: detail.duration !== undefined ? detail.duration : 5000, // Default 5s
  };

  // Persist to queue
  messageQueue.add(notification);

  // Dispatch event
  bus.dispatchEvent(new CustomEvent(NOTIFICATION_EVENT, {
    detail: notification
  }));

  // Log for debugging
  const logMethod = notification.type === NotificationType.ERROR ? 'error' : 'log';
  console[logMethod]('[DSS Notification]', {
    message: notification.message,
    code: notification.code,
    correlationId: notification.correlationId,
    metadata: notification.metadata,
  });

  return notification;
}

/**
 * Subscribe to notifications
 *
 * @param {Function} callback - Called when notification is sent
 * @returns {Function} Unsubscribe function
 *
 * @example
 * const unsubscribe = subscribe((notification) => {
 *   console.log('Notification:', notification.message);
 * });
 *
 * // Later: unsubscribe();
 */
export function subscribe(callback) {
  const handler = (event) => callback(event.detail);
  bus.addEventListener(NOTIFICATION_EVENT, handler);

  // Return unsubscribe function
  return () => {
    bus.removeEventListener(NOTIFICATION_EVENT, handler);
  };
}

/**
 * Helper: Send success notification
 * @param {string} message - Success message
 * @param {string} [code] - Success code
 * @param {Object} [metadata] - Additional context
 */
export function notifySuccess(message, code = ErrorCode.SUCCESS_OPERATION, metadata = {}) {
  return notify({
    message,
    type: NotificationType.SUCCESS,
    code,
    metadata,
  });
}

/**
 * Helper: Send error notification
 * @param {string} message - Error message
 * @param {string} [code] - Error code
 * @param {Object} [metadata] - Additional context
 */
export function notifyError(message, code = ErrorCode.SYSTEM_UNEXPECTED, metadata = {}) {
  return notify({
    message,
    type: NotificationType.ERROR,
    code,
    metadata,
    duration: 0, // Errors don't auto-dismiss
  });
}

/**
 * Helper: Send warning notification
 * @param {string} message - Warning message
 * @param {Object} [metadata] - Additional context
 */
export function notifyWarning(message, metadata = {}) {
  return notify({
    message,
    type: NotificationType.WARNING,
    metadata,
    duration: 7000, // Warnings stay a bit longer
  });
}

/**
 * Helper: Send info notification
 * @param {string} message - Info message
 * @param {Object} [metadata] - Additional context
 */
export function notifyInfo(message, metadata = {}) {
  return notify({
    message,
    type: NotificationType.INFO,
    metadata,
  });
}

/**
 * Get message history
 * @returns {Array} All persisted messages
 */
export function getMessageHistory() {
  return messageQueue.getAll();
}

/**
 * Get recent errors for debugging
 * @param {number} limit - Max number of errors
 * @returns {Array} Recent errors
 */
export function getRecentErrors(limit = 10) {
  return messageQueue.getRecentErrors(limit);
}

/**
 * Clear message history
 */
export function clearMessageHistory() {
  messageQueue.clear();
}

// Export singleton queue for advanced use cases
export { messageQueue };

export default {
  notify,
  subscribe,
  notifySuccess,
  notifyError,
  notifyWarning,
  notifyInfo,
  getMessageHistory,
  getRecentErrors,
  clearMessageHistory,
  NotificationType,
  ErrorCode,
};
