import { useCallback, useEffect, useState } from 'react' import { invoke } from '@tauri-apps/api/core' import { isTauri } from '../mock-tauri' import { trackEvent } from '../lib/telemetry' import { INITIAL_GUANGHU_ROUTER_STATE, markGuanghuAuthorizationApproved, reduceGuanghuRouterEvent, type GuanghuAuthorizationCard, type GuanghuRouterState, } from '../lib/guanghuRouter' const ROUTER_EVENT = 'guanghu-router-event' function initialRouterState(): GuanghuRouterState { if ( import.meta.env.DEV && typeof window !== 'undefined' && new URLSearchParams(window.location.search).get('world-preview') === 'online' ) { return { cards: [], error: null, latestReceipt: { connection_id: 'local-visual-preview', node_id: 'JD-FD-PRIMARY', receipt_id: 'local-visual-preview', state: 'online', }, status: 'online', } } return INITIAL_GUANGHU_ROUTER_STATE } function errorText(error: unknown): string { return error instanceof Error ? error.message : String(error) } export function useGuanghuRouter(): { approve: (card: GuanghuAuthorizationCard) => Promise connect: () => Promise disconnect: () => Promise probeRepository: (repositoryPath: string) => Promise requestRepositoryUpload: (repositoryPath: string) => Promise state: GuanghuRouterState } { const [state, setState] = useState(initialRouterState) useEffect(() => { if (!isTauri()) return let active = true let unlisten: (() => void) | null = null void import('@tauri-apps/api/event').then(({ listen }) => ( listen(ROUTER_EVENT, event => { if (active) setState(current => reduceGuanghuRouterEvent(current, event.payload)) }) )).then(stop => { if (active) unlisten = stop else stop() }).catch(error => { if (active) { setState(current => ({ ...current, error: `guanghu_router_event_listener_failed: ${errorText(error)}`, status: 'error', })) } }) return () => { active = false unlisten?.() } }, []) const connect = useCallback(async () => { if (!isTauri()) { setState(current => ({ ...current, error: 'guanghu_router_desktop_runtime_required', status: 'error', })) return } setState(current => ({ ...current, error: null, status: 'connecting' })) trackEvent('guanghu_router_connect_requested', { node: 'JD-FD-PRIMARY' }) try { const event = await invoke('guanghu_router_connect') setState(current => reduceGuanghuRouterEvent(current, event)) trackEvent('guanghu_router_connect_completed', { node: 'JD-FD-PRIMARY', result: 'online' }) } catch (error) { const reason = errorText(error) setState(current => ({ ...current, error: reason, status: 'error' })) trackEvent('guanghu_router_connect_completed', { node: 'JD-FD-PRIMARY', result: 'error', reason }) } }, []) const disconnect = useCallback(async () => { if (!isTauri()) return try { await invoke('guanghu_router_disconnect') setState(current => ({ ...current, error: null, status: 'offline' })) trackEvent('guanghu_router_disconnected', { node: 'JD-FD-PRIMARY' }) } catch (error) { setState(current => ({ ...current, error: errorText(error), status: 'error' })) } }, []) const approve = useCallback(async (card: GuanghuAuthorizationCard) => { if (!isTauri()) return try { const response = await invoke('guanghu_router_approve', { digest: card.digest, workorderId: card.workorder.id, }) setState(current => markGuanghuAuthorizationApproved( current, card.workorder.id, response, )) trackEvent('guanghu_router_authorization_decided', { action: card.workorder.action, node: card.workorder.target, result: 'approved', scope: card.workorder.scope, }) } catch (error) { setState(current => ({ ...current, error: errorText(error) })) } }, []) const probeRepository = useCallback(async (repositoryPath: string) => { if (!isTauri()) throw new Error('guanghu_router_desktop_runtime_required') return invoke('guanghu_router_probe_repository', { repositoryPath }) }, []) const requestRepositoryUpload = useCallback(async (repositoryPath: string) => { if (!isTauri()) throw new Error('guanghu_router_desktop_runtime_required') const response = await invoke('guanghu_router_request_repository_upload', { repositoryPath, }) trackEvent('guanghu_router_repository_upload_requested', { node: 'JD-FD-PRIMARY', repositoryPath, }) return response }, []) return { approve, connect, disconnect, probeRepository, requestRepositoryUpload, state, } }