/**
 * 文件职责：SignalR 连接管理 Hook，提供自动重连、事件订阅、断线补偿能力。
 */
import type { HubConnection } from '@microsoft/signalr';

import { ref } from 'vue';

import { useAppConfig } from '@vben/hooks';
import { useAccessStore } from '@vben/stores';

import {
  HubConnectionBuilder,
  HubConnectionState,
  LogLevel,
} from '@microsoft/signalr';

/** SignalR Hook 配置。 */
export interface UseSignalROptions {
  /** 重连后的补偿回调（传入断线时间戳）。 */
  onReconnected?: (lastDisconnectedAt: Date) => void;
  /** 连接关闭回调。 */
  onClose?: (error?: Error) => void;
}

/** SignalR 连接管理 Hook。 */
export function useSignalR(options?: UseSignalROptions) {
  const isConnected = ref(false);
  let connection: HubConnection | null = null;
  let lastDisconnectedAt: Date | null = null;

  // 1. 构建 Hub URL（从 apiURL 去掉 /api/tenant/v1 后缀）
  function buildHubUrl(): string {
    const { apiURL } = useAppConfig(import.meta.env, import.meta.env.PROD);
    const base = apiURL.replace(/\/api\/tenant\/v\d+\/?$/, '');
    return `${base}/hubs/order-board`;
  }

  // 2. 获取 JWT Token
  function getAccessToken(): string {
    const accessStore = useAccessStore();
    return accessStore.accessToken || '';
  }

  // 3. 建立连接
  async function connect(storeId?: string): Promise<void> {
    if (connection?.state === HubConnectionState.Connected) {
      return;
    }

    const hubUrl = storeId
      ? `${buildHubUrl()}?storeId=${storeId}`
      : buildHubUrl();

    connection = new HubConnectionBuilder()
      .withUrl(hubUrl, {
        accessTokenFactory: () => getAccessToken(),
      })
      .withAutomaticReconnect([0, 2000, 5000, 10_000, 30_000])
      .configureLogging(LogLevel.Warning)
      .build();

    // 4. 重连成功回调
    connection.onreconnecting(() => {
      isConnected.value = false;
      lastDisconnectedAt = new Date();
    });

    connection.onreconnected(() => {
      isConnected.value = true;
      if (lastDisconnectedAt && options?.onReconnected) {
        options.onReconnected(lastDisconnectedAt);
      }
      lastDisconnectedAt = null;
    });

    // 5. 连接关闭回调
    connection.onclose((error) => {
      isConnected.value = false;
      lastDisconnectedAt = new Date();
      options?.onClose?.(error ?? undefined);
    });

    await connection.start();
    isConnected.value = true;
  }

  // 6. 断开连接
  async function disconnect(): Promise<void> {
    if (connection) {
      await connection.stop();
      connection = null;
      isConnected.value = false;
    }
  }

  // 7. 订阅事件
  function on<T = unknown>(event: string, callback: (data: T) => void): void {
    connection?.on(event, callback);
  }

  // 8. 取消订阅
  function off(event: string): void {
    connection?.off(event);
  }

  // 9. 调用 Hub 方法
  async function invoke(method: string, ...args: unknown[]): Promise<void> {
    if (connection?.state === HubConnectionState.Connected) {
      await connection.invoke(method, ...args);
    }
  }

  return {
    isConnected,
    connect,
    disconnect,
    on,
    off,
    invoke,
  };
}
