import * as signalR from '@microsoft/signalr';
import { useAccessStore } from '@vben/stores';

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

class SignalRService {
  private connection: signalR.HubConnection | null = null;
  private reconnectAttempts = 0;
  private maxReconnectAttempts = 10;

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

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

    if (!token) return;

    this.connection = new signalR.HubConnectionBuilder()
      .withUrl('http://localhost:5212/hubs/chat', {
        accessTokenFactory: () => token,
      })
      .withAutomaticReconnect([0, 2000, 5000, 10000, 30000])
      .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 sendMessage(request: {
    conversationId: string;
    contentType: number;
    content: string;
    metadata?: any;
    replyToId?: string;
  }) {
    await this.connection?.invoke('SendMessage', request);
  }

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

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

  get isConnected() {
    return this.connection?.state === signalR.HubConnectionState.Connected;
  }
}

export const signalRService = new SignalRService();
