import type { ImApi } from './im';

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

import * as signalR from '@microsoft/signalr';

class SignalRService {
  onMessageRead:
    | ((data: { messageId: string; userId: string }) => void)
    | null = null;
  onMessageReceived: ((message: ImApi.Message) => void) | null = null;
  onUserOffline: ((data: { userId: string }) => void) | null = null;

  onUserOnline: ((data: { userId: string }) => void) | null = null;
  onUserTyping:
    | ((data: { conversationId: string; userId: string }) => void)
    | null = null;
  get isConnected() {
    return this.connection?.state === signalR.HubConnectionState.Connected;
  }
  private connection: null | signalR.HubConnection = null;
  private reconnectAttempts = 0;

  async connect() {
    const accessStore = useAccessStore();
    const token = accessStore.accessToken;

    if (!token) return;

    const signalrURL =
      import.meta.env.VITE_IM_SIGNALR_URL || '/im-signalr/hubs/chat';

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

    this.connection.on('OnMessageReceived', (message: ImApi.Message) => {
      this.onMessageReceived?.(message);
    });

    this.connection.on(
      'OnMessageRead',
      (data: { messageId: string; userId: string }) => {
        this.onMessageRead?.(data);
      },
    );

    this.connection.on(
      'OnUserTyping',
      (data: { conversationId: string; userId: string }) => {
        this.onUserTyping?.(data);
      },
    );

    this.connection.on('OnUserOnline', (data: { userId: string }) => {
      this.onUserOnline?.(data);
    });

    this.connection.on('OnUserOffline', (data: { userId: string }) => {
      this.onUserOffline?.(data);
    });

    this.connection.onreconnected(() => {
      this.reconnectAttempts = 0;
    });

    this.connection.onclose(() => {
      this.reconnectAttempts++;
    });

    try {
      await this.connection.start();
    } catch (error) {
      console.error('SignalR connection error:', error);
    }
  }

  async disconnect() {
    if (this.connection) {
      await this.connection.stop();
      this.connection = null;
    }
  }

  async markAsRead(conversationId: string, messageId: string) {
    await this.connection?.invoke('MarkAsRead', { conversationId, messageId });
  }

  async sendMessage(request: {
    content: string;
    contentType: number;
    conversationId: string;
    metadata?: any;
    replyToId?: string;
  }) {
    await this.connection?.invoke('SendMessage', request);
  }

  async typing(conversationId: string) {
    await this.connection?.invoke('Typing', conversationId);
  }
}

export const signalRService = new SignalRService();
