/**
 * @deprecated Scheduled for removal in v2.0.0
 * --------------------------------------------------------------------------
 * ⚠️ NOTICE: V2 DATA&UI REFACTORING (by 0xfullex)
 * --------------------------------------------------------------------------
 * STOP: Feature PRs affecting this file are currently BLOCKED.
 * Only critical bug fixes are accepted during this migration phase.
 *
 * This file is being refactored to v2 standards.
 * Any non-critical changes will conflict with the ongoing work.
 *
 * 🔗 Context & Status:
 * - Contribution Hold: https://github.com/CherryHQ/cherry-studio/issues/10954
 * - v2 Refactor PR   : https://github.com/CherryHQ/cherry-studio/pull/10162
 * --------------------------------------------------------------------------
 */
import { IpcChannel } from '@shared/IpcChannel'
import type { StoreSyncAction } from '@types'
import { BrowserWindow, ipcMain } from 'electron'

/**
 * StoreSyncService class manages Redux store synchronization between multiple windows in the main process
 * It uses singleton pattern to ensure only one sync service instance exists in the application
 *
 * Main features:
 * 1. Manages window subscriptions for store sync
 * 2. Handles IPC communication for store sync between windows
 * 3. Broadcasts Redux actions from one window to all other windows
 * 4. Adds metadata to synced actions to prevent infinite sync loops
 */
export class StoreSyncService {
  private static instance: StoreSyncService
  private windowIds: number[] = []
  private isIpcHandlerRegistered = false

  private constructor() {
    return
  }

  /**
   * Get the singleton instance of StoreSyncService
   */
  public static getInstance(): StoreSyncService {
    if (!StoreSyncService.instance) {
      StoreSyncService.instance = new StoreSyncService()
    }
    return StoreSyncService.instance
  }

  /**
   * Subscribe a window to store sync
   * @param windowId ID of the window to subscribe
   */
  public subscribe(windowId: number): void {
    if (!this.windowIds.includes(windowId)) {
      this.windowIds.push(windowId)
    }
  }

  /**
   * Unsubscribe a window from store sync
   * @param windowId ID of the window to unsubscribe
   */
  public unsubscribe(windowId: number): void {
    this.windowIds = this.windowIds.filter((id) => id !== windowId)
  }

  /**
   * Sync an action to all renderer windows
   * @param type Action type, like 'settings/setTray'
   * @param payload Action payload
   *
   * NOTICE: DO NOT use directly in ConfigManager, may cause infinite sync loop
   */
  public syncToRenderer(type: string, payload: any): void {
    const action: StoreSyncAction = {
      type,
      payload
    }

    //-1 means the action is from the main process, will be broadcast to all windows
    this.broadcastToOtherWindows(-1, action)
  }

  /**
   * Register IPC handlers for store sync communication
   * Handles window subscription, unsubscription and action broadcasting
   */
  public registerIpcHandler(): void {
    if (this.isIpcHandlerRegistered) return

    ipcMain.handle(IpcChannel.StoreSync_Subscribe, (event) => {
      const windowId = BrowserWindow.fromWebContents(event.sender)?.id
      if (windowId) {
        this.subscribe(windowId)
      }
    })

    ipcMain.handle(IpcChannel.StoreSync_Unsubscribe, (event) => {
      const windowId = BrowserWindow.fromWebContents(event.sender)?.id
      if (windowId) {
        this.unsubscribe(windowId)
      }
    })

    ipcMain.handle(IpcChannel.StoreSync_OnUpdate, (event, action: StoreSyncAction) => {
      const sourceWindowId = BrowserWindow.fromWebContents(event.sender)?.id

      if (!sourceWindowId) return

      // Broadcast the action to all other windows
      this.broadcastToOtherWindows(sourceWindowId, action)
    })

    this.isIpcHandlerRegistered = true
  }

  /**
   * Broadcast a Redux action to all other windows except the source
   * @param sourceWindowId ID of the window that originated the action
   * @param action Redux action to broadcast
   */
  private broadcastToOtherWindows(sourceWindowId: number, action: StoreSyncAction): void {
    // Add metadata to indicate this action came from sync
    const syncAction = {
      ...action,
      meta: {
        ...action.meta,
        fromSync: true,
        source: `windowId:${sourceWindowId}`
      }
    }

    // Send to all windows except the source
    this.windowIds.forEach((windowId) => {
      if (windowId !== sourceWindowId) {
        const targetWindow = BrowserWindow.fromId(windowId)
        if (targetWindow && !targetWindow.isDestroyed()) {
          targetWindow.webContents.send(IpcChannel.StoreSync_BroadcastSync, syncAction)
        } else {
          this.unsubscribe(windowId)
        }
      }
    })
  }
}

// Export singleton instance
export default StoreSyncService.getInstance()
