import {Meta} from '@storybook/addon-docs/blocks'

<Meta title='@dxtmisha/functional/en/Classes/BroadcastMessage'/>

# BroadcastMessage Class

A class for handling BroadcastChannel messaging between browser tabs/windows. Enables real-time communication across different contexts of the same origin with automatic channel naming and message handling.

## Key Features

- **Cross-tab communication** — send and receive messages between browser tabs and windows
- **Automatic channel naming** — unique channel names per browser instance stored in localStorage
- **Type-safe messaging** — full TypeScript support with generic message types
- **Callback-based handling** — flexible message handling through callback functions
- **Error handling** — graceful error handling with console logging
- **SSR-safe** — automatically detects DOM runtime environment

## Basic Usage

### Constructor

Creates a new BroadcastMessage instance with specified channel name and optional callback.

**Parameters:**
- `name: string` — channel name identifier
- `callback?: (event: MessageEvent<Message>) => void` — optional callback for received messages

```javascript
import { BroadcastMessage } from '@dxtmisha/functional'

// Create channel with callback
const channel = new BroadcastMessage('user-updates', (event) => {
  console.log('Received message:', event.data)
})

// Create channel without callback (can be set later)
const notifications = new BroadcastMessage('notifications')
```

### `post`

Sends a message to all connected tabs/windows on the same channel.

**Parameters:**
- `message: Message` — message to broadcast

**Returns:** `this` — for method chaining

```javascript
import { BroadcastMessage } from '@dxtmisha/functional'

const userChannel = new BroadcastMessage('user-updates')

// Send simple message
userChannel.post({ type: 'login', userId: 123 })

// Method chaining
userChannel
  .post({ type: 'status', value: 'online' })
  .post({ type: 'activity', timestamp: Date.now() })
```

### `setCallback`

Sets or updates the callback function for handling received messages.

**Parameters:**
- `callback: (event: MessageEvent<Message>) => void` — callback function

**Returns:** `this` — for method chaining

```javascript
import { BroadcastMessage } from '@dxtmisha/functional'

const channel = new BroadcastMessage('app-events')

// Set callback later
channel.setCallback((event) => {
  console.log('Event received:', event.data)
})

// Update callback
channel.setCallback((event) => {
  if (event.data.type === 'refresh') {
    location.reload()
  }
})
```

## Advanced Examples

### Cross-Tab State Synchronization

```javascript
import { BroadcastMessage } from '@dxtmisha/functional'
import { ref } from 'vue'

// Create reactive state
const userStatus = ref('offline')

// Create broadcast channel
const statusChannel = new BroadcastMessage('user-status', (event) => {
  // Update local state when other tabs broadcast changes
  userStatus.value = event.data.status
  console.log('Status updated from another tab:', event.data.status)
})

// Function to update status and broadcast to other tabs
function updateStatus(newStatus) {
  userStatus.value = newStatus
  statusChannel.post({ status: newStatus, timestamp: Date.now() })
}

// Usage
updateStatus('online')  // Updates this tab and notifies others
```

### Multi-Tab Shopping Cart

```javascript
import { BroadcastMessage } from '@dxtmisha/functional'

// Define message types
interface CartMessage {
  action: 'add' | 'remove' | 'clear'
  productId?: number
  quantity?: number
}

// Create channel with typed messages
const cartChannel = new BroadcastMessage<CartMessage>('shopping-cart')

// Set up message handler
cartChannel.setCallback((event) => {
  const { action, productId, quantity } = event.data

  switch (action) {
    case 'add':
      console.log(`Adding ${quantity} of product ${productId}`)
      addToCart(productId, quantity)
      break
    case 'remove':
      console.log(`Removing product ${productId}`)
      removeFromCart(productId)
      break
    case 'clear':
      console.log('Clearing cart')
      clearCart()
      break
  }
})

// Broadcast cart updates
function addProduct(productId, quantity) {
  addToCart(productId, quantity)
  cartChannel.post({ action: 'add', productId, quantity })
}
```

### Authentication State Sync

```javascript
import { BroadcastMessage } from '@dxtmisha/functional'

interface AuthMessage {
  type: 'login' | 'logout' | 'token-refresh'
  userId?: number
  token?: string
}

const authChannel = new BroadcastMessage<AuthMessage>('auth-events', (event) => {
  switch (event.data.type) {
    case 'login':
      console.log('User logged in:', event.data.userId)
      location.reload()
      break

    case 'logout':
      console.log('User logged out, redirecting...')
      localStorage.removeItem('auth-token')
      window.location.href = '/login'
      break

    case 'token-refresh':
      console.log('Token refreshed')
      localStorage.setItem('auth-token', event.data.token)
      break
  }
})

// Broadcast login
function handleLogin(userId, token) {
  localStorage.setItem('auth-token', token)
  authChannel.post({ type: 'login', userId, token })
}

// Broadcast logout
function handleLogout() {
  localStorage.removeItem('auth-token')
  authChannel.post({ type: 'logout' })
}
```

### Real-Time Notifications

```javascript
import { BroadcastMessage } from '@dxtmisha/functional'

interface Notification {
  id: string
  title: string
  message: string
  type: 'info' | 'warning' | 'error' | 'success'
  timestamp: number
}

const notificationChannel = new BroadcastMessage<Notification>('notifications')

// Set up notification handler
notificationChannel.setCallback((event) => {
  const notification = event.data

  // Display notification in all tabs
  showNotification(notification.title, notification.message, notification.type)

  if (notification.type === 'error') {
    playErrorSound()
  }
})

// Send notification to all tabs
function broadcastNotification(title, message, type = 'info') {
  const notification = {
    id: crypto.randomUUID(),
    title,
    message,
    type,
    timestamp: Date.now()
  }

  notificationChannel.post(notification)
}

// Usage
broadcastNotification('New Message', 'You have a new message from John', 'info')
```

## Implementation Details

### Unique Channel Naming

Each browser instance generates a unique identifier stored in localStorage (`__broadcast-name`). This ensures that channels are isolated between different browser instances while allowing communication within the same instance across tabs.

```javascript
// Channel name format: name_{random_7_digits}__your-channel-name
// Example: name_1234567__user-updates
```

### Error Handling

BroadcastMessage gracefully handles errors and logs them to console:

```javascript
const channel = new BroadcastMessage('my-channel')
// If BroadcastChannel is not supported or initialization fails,
// error is logged: "BroadcastMessage my-channel: [error details]"
```

### SSR Compatibility

The class automatically detects DOM runtime environment using `isDomRuntime()`, making it safe to use in SSR/SSG contexts where BroadcastChannel API is not available.

## Type Safety

```typescript
import { BroadcastMessage } from '@dxtmisha/functional'

// Define your message structure
interface UserUpdate {
  userId: number
  action: 'online' | 'offline' | 'typing'
  timestamp: number
}

// Create typed channel
const channel = new BroadcastMessage<UserUpdate>('users')

// TypeScript ensures type safety
channel.post({
  userId: 123,
  action: 'online',
  timestamp: Date.now()
}) // ✓ Valid

channel.post({ invalid: 'data' }) // ✗ TypeScript error
```

## Browser Compatibility

BroadcastChannel API is supported in:
- Chrome/Edge 54+
- Firefox 38+
- Safari 15.4+
- Opera 41+

For older browsers, consider using a polyfill or fallback mechanism.

