import { defineStore } from 'pinia';
import { ref, computed, shallowRef } from 'vue';
import { io, type Socket } from 'socket.io-client';
import type {
  ServerToClientEvents,
  ClientToServerEvents,
  ConnectionAckPayload,
  VoteCategory,
  SyncStatePayload,
  AdminState,
} from '@gala/shared/types';
import { SOCKET_EVENTS } from '@gala/shared/constants';
import { CONFIG } from '@gala/shared/constants';

type GalaSocket = Socket<ServerToClientEvents, ClientToServerEvents>;

export const useConnectionStore = defineStore('connection', () => {
  // State - use shallowRef for socket to avoid deep reactivity issues
  const socket = shallowRef<GalaSocket | null>(null);
  const isConnected = ref(false);
  const isConnecting = ref(false);
  const sessionId = ref<string | null>(null);
  const lastPingTime = ref<number>(0);
  const latency = ref<number>(0);
  const reconnectAttempts = ref(0);
  const userId = ref<string | null>(null);
  const userName = ref<string | null>(null);
  const department = ref<string | null>(null);
  const votedCategories = ref<VoteCategory[]>([]);

  // Computed
  const connectionStatus = computed(() => {
    if (isConnected.value) return 'connected';
    if (isConnecting.value) return 'connecting';
    return 'disconnected';
  });

  const remainingVotes = computed(() => {
    return CONFIG.MAX_VOTES_PER_USER - votedCategories.value.length;
  });

  // Heartbeat interval
  let heartbeatInterval: ReturnType<typeof setInterval> | null = null;
  let pongTimeout: ReturnType<typeof setTimeout> | null = null;

  /**
   * Connect to WebSocket server
   */
  function connect() {
    if (socket.value?.connected || isConnecting.value) {
      return;
    }

    isConnecting.value = true;

    const socketInstance = io(import.meta.env.VITE_SOCKET_URL || '', {
      reconnection: true,
      reconnectionAttempts: Infinity,
      reconnectionDelay: CONFIG.RECONNECTION_DELAY_MS,
      reconnectionDelayMax: CONFIG.RECONNECTION_DELAY_MAX_MS,
      timeout: CONFIG.HEARTBEAT_TIMEOUT_MS,
      transports: ['websocket', 'polling'],
    });

    // Connection events
    socketInstance.on('connect', () => {
      console.log('[Socket] Connected');
      isConnected.value = true;
      isConnecting.value = false;
      reconnectAttempts.value = 0;

      // Auto-generate userId if not set
      if (!userId.value) {
        userId.value = `user_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
        userName.value = '访客';
      }

      // Join with user info
      joinRoom();

      // Start heartbeat
      startHeartbeat();
    });

    socketInstance.on('disconnect', (reason) => {
      console.log('[Socket] Disconnected:', reason);
      isConnected.value = false;
      stopHeartbeat();
    });

    socketInstance.on('connect_error', (error) => {
      console.error('[Socket] Connection error:', error);
      isConnecting.value = false;
      reconnectAttempts.value++;
    });

    // Custom pong handler
    socketInstance.on('connection:pong' as any, () => {
      if (pongTimeout) {
        clearTimeout(pongTimeout);
        pongTimeout = null;
      }
      latency.value = Date.now() - lastPingTime.value;
    });

    // Connection acknowledgment
    socketInstance.on('connection:ack' as any, (data: ConnectionAckPayload) => {
      sessionId.value = data.sessionId;
      if (data.reconnected && data.missedEvents) {
        // Handle missed events
        console.log('[Socket] Reconnected, processing missed events');
      }
    });

    // Sync state
    socketInstance.on('sync:state' as any, (data: SyncStatePayload) => {
      if (data.userVotedCategories) {
        votedCategories.value = data.userVotedCategories;
      }
    });
    // Admin state sync - update voting state
    socketInstance.on(SOCKET_EVENTS.ADMIN_STATE_SYNC as any, (state: AdminState) => {
      console.log('[Socket] Admin state sync received');
      // Dynamically import voting store to avoid circular dependency
      import('./voting').then(({ useVotingStore }) => {
        const votingStore = useVotingStore();
        votingStore.syncVotingState({
          votingOpen: state.voting.subPhase === 'OPEN',
          votingPaused: state.voting.subPhase === 'PAUSED',
          programs: state.voting.programs,
          currentProgramId: state.voting.currentProgramId,
          allowLateCatch: state.voting.allowLateCatch,
        });
      });
    });

    // Remote vote update (from other users)
    socketInstance.on(SOCKET_EVENTS.VOTE_UPDATED as any, (data: any) => {
      import('./voting').then(({ useVotingStore }) => {
        const votingStore = useVotingStore();
        votingStore.handleVoteUpdate(data);
      });
    });

    socket.value = socketInstance as GalaSocket;
  }

  /**
   * Join room with user info
   */
  function joinRoom() {
    if (!socket.value || !userId.value) return;

    socket.value.emit(
      SOCKET_EVENTS.CONNECTION_JOIN as any,
      {
        userId: userId.value,
        userName: userName.value || 'Guest',
        department: department.value || '未知部门',
        role: 'user',
      },
      (response: any) => {
        if (response.success) {
          sessionId.value = response.data.sessionId;
          if (response.data.votedCategories) {
            votedCategories.value = response.data.votedCategories;
          }
        }
      }
    );
  }

  /**
   * Start heartbeat
   */
  function startHeartbeat() {
    stopHeartbeat();

    heartbeatInterval = setInterval(() => {
      if (socket.value?.connected) {
        lastPingTime.value = Date.now();
        socket.value.emit(SOCKET_EVENTS.CONNECTION_PING as any);

        // Set pong timeout
        pongTimeout = setTimeout(() => {
          console.warn('[Socket] Pong timeout, connection may be unstable');
        }, CONFIG.HEARTBEAT_TIMEOUT_MS);
      }
    }, CONFIG.HEARTBEAT_INTERVAL_MS);
  }

  /**
   * Stop heartbeat
   */
  function stopHeartbeat() {
    if (heartbeatInterval) {
      clearInterval(heartbeatInterval);
      heartbeatInterval = null;
    }
    if (pongTimeout) {
      clearTimeout(pongTimeout);
      pongTimeout = null;
    }
  }

  /**
   * Disconnect from server
   */
  function disconnect() {
    stopHeartbeat();
    if (socket.value) {
      socket.value.disconnect();
      socket.value = null;
    }
    isConnected.value = false;
    isConnecting.value = false;
  }

  /**
   * Set user info
   */
  function setUser(id: string, name: string, dept: string) {
    userId.value = id;
    userName.value = name;
    department.value = dept;

    // Rejoin if already connected
    if (socket.value?.connected) {
      joinRoom();
    }
  }

  /**
   * Add voted category
   */
  function addVotedCategory(category: VoteCategory) {
    if (!votedCategories.value.includes(category)) {
      votedCategories.value.push(category);
    }
  }

  /**
   * Request sync from server
   */
  function requestSync() {
    if (socket.value?.connected) {
      socket.value.emit(SOCKET_EVENTS.SYNC_REQUEST as any, {});
    }
  }

  /**
   * Get socket instance (for advanced usage)
   */
  function getSocket(): GalaSocket | null {
    return socket.value;
  }

  return {
    // State (excluding socket to avoid type inference issues)
    isConnected,
    isConnecting,
    sessionId,
    latency,
    reconnectAttempts,
    userId,
    userName,
    department,
    votedCategories,

    // Computed
    connectionStatus,
    remainingVotes,

    // Actions
    connect,
    disconnect,
    setUser,
    addVotedCategory,
    requestSync,
    getSocket,
  };
});
