import { io, Socket } from "socket.io-client";
import { BASE_URL } from "@/config/const";
import { getChatbotSessionId, setChatbotSessionId } from "../utils/cookies";
import { generateULID } from "../utils/ulid";
import {
  ChatSession,
  SessionCreatedResponse,
  ChatJoinedResponse,
  MessageReceivedResponse,
  BotResponse,
  BotResponseStart,
  BotResponseChunk,
  BotResponseEnd,
  ErrorResponse,
  AuthenticatedResponse,
  UnauthorizedResponse,
  SendMessagePayload,
  ConnectionStatus,
} from "../types/Types";

class ChatbotSocketService {
  private socket: Socket | null = null;
  private eventListeners: { [key: string]: ((data: unknown) => void)[] } = {};
  private connectionStatus: ConnectionStatus = "disconnected";
  private reconnectAttempts = 0;
  private maxReconnectAttempts = 5;
  private reconnectDelay = 1000;

  constructor() {
    this.initializeEventListeners();
  }

  private initializeEventListeners(): void {
    this.eventListeners = {
      connect: [],
      disconnect: [],
      connection_failed: [],
      authenticated: [],
      unauthorized: [],
      session_created: [],
      chat_joined: [],
      chat_left: [],
      message_received: [],
      bot_response: [],
      bot_response_start: [],
      bot_response_chunk: [],
      bot_response_end: [],
      typing_start: [],
      typing_stop: [],
      user_joined: [],
      user_left: [],
      error: [],
      websocket_error: [],
      session_error: [],
      message_error: [],
      connection_status_changed: [],
    };
  }

  connect(token?: string): Promise<void> {
    return new Promise((resolve, reject) => {
      try {
        this.connectionStatus = "connecting";
        this.emit("connection_status_changed", this.connectionStatus);

        // اگر session ID وجود ندارد، یکی بساز
        let sessionId = getChatbotSessionId();
        if (!sessionId) {
          sessionId = generateULID();
          setChatbotSessionId(sessionId);
        }

        const connectionOptions: {
          path: string;
          query?: Record<string, string>;
          transports: string[];
          timeout: number;
          reconnection: boolean;
          reconnectionAttempts: number;
          reconnectionDelay: number;
          reconnectionDelayMax: number;
        } = {
          path: "/ws-chatbot",
          transports: ["websocket"],
          timeout: 10000,
          reconnection: true,
          reconnectionAttempts: this.maxReconnectAttempts,
          reconnectionDelay: this.reconnectDelay,
          reconnectionDelayMax: 5000,
        };

        // اگر token وجود دارد، از آن استفاده کن
        if (token) {
          connectionOptions.query = { token };
        }

        console.log("🔌 اتصال به chatbot socket:", `${BASE_URL}/ws-chatbot`);

        this.socket = io(BASE_URL, connectionOptions);

        this.setupSocketListeners();

        // مدیریت اتصال موفق
        this.socket.on("connect", () => {
          console.log("✅ اتصال chatbot socket برقرار شد:", this.socket?.id);
          this.connectionStatus = "connected";
          this.reconnectAttempts = 0;
          this.emit("connection_status_changed", this.connectionStatus);
          this.emit("connect", null);
          resolve();
        });

        // مدیریت خطای اتصال
        this.socket.on("connect_error", (err) => {
          console.error("❌ خطا در اتصال chatbot socket:", err.message);
          this.connectionStatus = "error";
          this.emit("connection_status_changed", this.connectionStatus);
          this.emit("connection_failed", err);
          reject(err);
        });

        // مدیریت قطع اتصال
        this.socket.on("disconnect", (reason) => {
          console.log("❌ اتصال chatbot socket قطع شد:", reason);
          if (reason === "io server disconnect") {
            this.connectionStatus = "disconnected";
          } else {
            this.connectionStatus = "reconnecting";
          }
          this.emit("connection_status_changed", this.connectionStatus);
          this.emit("disconnect", reason);
        });

        // مدیریت reconnect
        this.socket.io.on("reconnect_attempt", () => {
          this.reconnectAttempts++;
          this.connectionStatus = "reconnecting";
          this.emit("connection_status_changed", this.connectionStatus);
          console.log(
            `🔄 تلاش برای اتصال مجدد (${this.reconnectAttempts}/${this.maxReconnectAttempts})`
          );
        });

        this.socket.io.on("reconnect", () => {
          console.log("✅ اتصال مجدد برقرار شد");
          this.connectionStatus = "connected";
          this.reconnectAttempts = 0;
          this.emit("connection_status_changed", this.connectionStatus);
        });

        this.socket.io.on("reconnect_failed", () => {
          console.error("❌ اتصال مجدد ناموفق");
          this.connectionStatus = "error";
          this.emit("connection_status_changed", this.connectionStatus);
        });
      } catch (error) {
        console.error("خطا در ایجاد اتصال chatbot socket:", error);
        this.connectionStatus = "error";
        this.emit("connection_status_changed", this.connectionStatus);
        reject(error);
      }
    });
  }

  private setupSocketListeners(): void {
    if (!this.socket) return;

    // Authentication events
    this.socket.on("authenticated", (data: AuthenticatedResponse) => {
      console.log("✅ احراز هویت موفق:", data);
      this.emit("authenticated", data);
    });

    this.socket.on("unauthorized", (data: UnauthorizedResponse) => {
      console.error("❌ احراز هویت ناموفق:", data);
      this.emit("unauthorized", data);
    });

    // Session events
    this.socket.on("session_created", (data: SessionCreatedResponse) => {
      console.log("✅ سشن ایجاد شد:", data);
      this.emit("session_created", data);
    });

    this.socket.on("chat_joined", (data: ChatJoinedResponse) => {
      console.log("✅ به چت پیوست:", data);
      this.emit("chat_joined", data);
    });

    this.socket.on("chat_left", () => {
      console.log("✅ از چت خارج شد");
      this.emit("chat_left", null);
    });

    // Message events
    this.socket.on("message_received", (data: MessageReceivedResponse) => {
      console.log("💬 پیام دریافت شد:", data);
      this.emit("message_received", data);
    });

    // Bot response events (non-streaming)
    this.socket.on("bot_response", (data: BotResponse) => {
      console.log("🤖 پاسخ ربات:", data);
      this.emit("bot_response", data);
    });

    // Bot response events (streaming)
    this.socket.on("bot_response_start", (data: BotResponseStart) => {
      console.log("🤖 شروع پاسخ ربات:", data);
      this.emit("bot_response_start", data);
    });

    this.socket.on("bot_response_chunk", (data: BotResponseChunk) => {
      this.emit("bot_response_chunk", data);
    });

    this.socket.on("bot_response_end", (data: BotResponseEnd) => {
      console.log("🤖 پایان پاسخ ربات:", data);
      this.emit("bot_response_end", data);
    });

    // Typing events
    this.socket.on(
      "typing_start",
      (data: { sessionId: string; userId?: string }) => {
        this.emit("typing_start", data);
      }
    );

    this.socket.on(
      "typing_stop",
      (data: { sessionId: string; userId?: string }) => {
        this.emit("typing_stop", data);
      }
    );

    // User presence events
    this.socket.on(
      "user_joined",
      (data: { sessionId: string; userId: string }) => {
        console.log("👤 کاربر پیوست:", data);
        this.emit("user_joined", data);
      }
    );

    this.socket.on(
      "user_left",
      (data: { sessionId: string; userId: string }) => {
        console.log("👤 کاربر خارج شد:", data);
        this.emit("user_left", data);
      }
    );

    // Error events
    this.socket.on("error", (data: ErrorResponse) => {
      console.error("⚠️ خطای عمومی:", data);
      this.emit("error", data);
    });

    this.socket.on("websocket_error", (data: ErrorResponse) => {
      console.error("⚠️ خطای WebSocket:", data);
      this.emit("websocket_error", data);
    });

    this.socket.on("session_error", (data: ErrorResponse) => {
      console.error("⚠️ خطای سشن:", data);
      this.emit("session_error", data);
    });

    this.socket.on("message_error", (data: ErrorResponse) => {
      console.error("⚠️ خطای پیام:", data);
      this.emit("message_error", data);
    });
  }

  // Session management
  createSession(): void {
    if (this.socket && this.socket.connected) {
      console.log("📝 ایجاد سشن جدید");
      this.socket.emit("create_session");
    } else {
      console.error("سوکت متصل نیست - نمی‌توان سشن ایجاد کرد");
    }
  }

  joinChat(sessionId: string): void {
    if (this.socket && this.socket.connected) {
      console.log("🔗 ورود به چت:", sessionId);
      this.socket.emit("join_chat", sessionId);
    } else {
      console.error("سوکت متصل نیست - نمی‌توان به چت وارد شد");
    }
  }

  leaveChat(sessionId: string): void {
    if (this.socket && this.socket.connected) {
      console.log("🚪 خروج از چت:", sessionId);
      this.socket.emit("leave_chat", sessionId);
    }
  }

  // Message sending
  sendMessage(payload: SendMessagePayload): void {
    if (this.socket && this.socket.connected) {
      console.log("📤 ارسال پیام:", payload);
      this.socket.emit("send_message", payload);
    } else {
      console.error("سوکت متصل نیست - نمی‌توان پیام ارسال کرد");
    }
  }

  sendMessageStream(payload: SendMessagePayload): void {
    if (this.socket && this.socket.connected) {
      console.log("📤 ارسال پیام با streaming:", payload);
      this.socket.emit("send_message_stream", payload);
    } else {
      console.error("سوکت متصل نیست - نمی‌توان پیام ارسال کرد");
    }
  }

  // Typing indicators
  typingStart(sessionId: string): void {
    if (this.socket && this.socket.connected) {
      this.socket.emit("typing_start", sessionId);
    }
  }

  typingStop(sessionId: string): void {
    if (this.socket && this.socket.connected) {
      this.socket.emit("typing_stop", sessionId);
    }
  }

  // Connection management
  disconnect(): void {
    if (this.socket) {
      console.log("🔌 قطع اتصال chatbot socket");
      this.socket.disconnect();
      this.socket = null;
      this.connectionStatus = "disconnected";
      this.emit("connection_status_changed", this.connectionStatus);
    }
  }

  isConnected(): boolean {
    return this.socket?.connected || false;
  }

  getConnectionStatus(): ConnectionStatus {
    return this.connectionStatus;
  }

  // Event system
  on(event: string, callback: (data: unknown) => void): void {
    if (!this.eventListeners[event]) {
      this.eventListeners[event] = [];
    }
    this.eventListeners[event].push(callback);
  }

  off(event: string, callback: (data: unknown) => void): void {
    if (this.eventListeners[event]) {
      this.eventListeners[event] = this.eventListeners[event].filter(
        (cb) => cb !== callback
      );
    }
  }

  private emit(event: string, data: unknown): void {
    if (this.eventListeners[event]) {
      this.eventListeners[event].forEach((callback) => callback(data));
    }
  }
}

// ایجاد instance singleton
export const chatbotSocketService = new ChatbotSocketService();
