import { ref, shallowRef, onMounted, onUnmounted, readonly } from 'vue';
import { io, Socket } from 'socket.io-client';
import type {
  ServerToClientEvents,
  ClientToServerEvents,
  DrawStartPayload,
  DrawSpinPayload,
  DrawWinnerPayload,
  VoteUpdatePayload,
} from '@gala/shared/types';
import { SOCKET_EVENTS } from '@gala/shared/constants';

type GalaSocket = Socket<ServerToClientEvents, ClientToServerEvents>;

// ============================================================================
// Types
// ============================================================================

export interface LotteryState {
  phase: 'idle' | 'rolling' | 'revealing' | 'complete';
  prizeLevel: string | null;
  prizeName: string | null;
  participantCount: number;
  winners: Array<{
    odrawId: string;
    visitorId: string;
    userId: string;
    userName: string;
    department: string;
    avatar?: string;
  }>;
  spinningNames: string[];
}

export interface VoteEvent {
  candidateId: string;
  category: string;
  totalVotes: number;
  delta: number;
  timestamp: number;
}

export type VoteUpdateCallback = (event: VoteEvent) => void;
export type LotteryStateCallback = (state: LotteryState) => void;

// ============================================================================
// Composable
// ============================================================================

export function useSocketClient() {
  // Connection state
  const socket = shallowRef<GalaSocket | null>(null);
  const isConnected = ref(false);
  const isConnecting = ref(false);
  const onlineUsers = ref(0);
  const latency = ref(0);

  // Lottery state
  const lotteryState = ref<LotteryState>({
    phase: 'idle',
    prizeLevel: null,
    prizeName: null,
    participantCount: 0,
    winners: [],
    spinningNames: [],
  });

  // Event callbacks
  const voteCallbacks = new Set<VoteUpdateCallback>();
  const lotteryCallbacks = new Set<LotteryStateCallback>();

  // Heartbeat
  let heartbeatInterval: ReturnType<typeof setInterval> | null = null;
  let lastPingTime = 0;

  // ============================================================================
  // Connection Management
  // ============================================================================

  function connect(): void {
    if (socket.value?.connected || isConnecting.value) {
      return;
    }

    isConnecting.value = true;

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

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

      // Join as screen display
      socketInstance.emit(SOCKET_EVENTS.CONNECTION_JOIN as any, {
        userId: `screen_${Date.now()}`,
        userName: 'Big Screen Display',
        role: 'screen',
      }, () => {});

      // Start heartbeat
      startHeartbeat();
    });

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

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

    // User count updates
    socketInstance.on('connection:users_count' as any, (count: number) => {
      onlineUsers.value = count;
    });

    // Pong response
    socketInstance.on('connection:pong' as any, () => {
      latency.value = Date.now() - lastPingTime;
    });

    // Vote updates
    socketInstance.on('vote:updated' as any, (data: VoteUpdatePayload) => {
      const event: VoteEvent = {
        ...data,
        timestamp: Date.now(),
      };

      // Notify all registered callbacks
      voteCallbacks.forEach(cb => cb(event));
    });

    // Lottery events
    socketInstance.on('draw:started' as any, (data: DrawStartPayload) => {
      lotteryState.value = {
        phase: 'rolling',
        prizeLevel: data.prizeLevel,
        prizeName: data.prizeName,
        participantCount: data.participantCount,
        winners: [],
        spinningNames: [],
      };
      notifyLotteryCallbacks();
    });

    socketInstance.on('draw:spinning' as any, (data: DrawSpinPayload) => {
      lotteryState.value.spinningNames = data.currentNames;
      lotteryState.value.phase = 'rolling';
      notifyLotteryCallbacks();
    });

    socketInstance.on('draw:winner' as any, (data: DrawWinnerPayload) => {
      lotteryState.value.phase = 'revealing';
      lotteryState.value.winners.push(data.winner);
      notifyLotteryCallbacks();
    });

    socketInstance.on('draw:ended' as any, () => {
      lotteryState.value.phase = 'complete';
      notifyLotteryCallbacks();

      // Reset to idle after delay
      setTimeout(() => {
        lotteryState.value.phase = 'idle';
        notifyLotteryCallbacks();
      }, 10000);
    });

    socket.value = socketInstance as GalaSocket;
  }

  function disconnect(): void {
    stopHeartbeat();
    if (socket.value) {
      socket.value.disconnect();
      socket.value = null;
    }
    isConnected.value = false;
    isConnecting.value = false;
  }

  // ============================================================================
  // Heartbeat
  // ============================================================================

  function startHeartbeat(): void {
    stopHeartbeat();
    heartbeatInterval = setInterval(() => {
      if (socket.value?.connected) {
        lastPingTime = Date.now();
        socket.value.emit(SOCKET_EVENTS.CONNECTION_PING as any);
      }
    }, 5000);
  }

  function stopHeartbeat(): void {
    if (heartbeatInterval) {
      clearInterval(heartbeatInterval);
      heartbeatInterval = null;
    }
  }

  // ============================================================================
  // Event Subscription
  // ============================================================================

  function onVoteUpdate(callback: VoteUpdateCallback): () => void {
    voteCallbacks.add(callback);
    return () => voteCallbacks.delete(callback);
  }

  function onLotteryStateChange(callback: LotteryStateCallback): () => void {
    lotteryCallbacks.add(callback);
    return () => lotteryCallbacks.delete(callback);
  }

  function notifyLotteryCallbacks(): void {
    lotteryCallbacks.forEach(cb => cb(lotteryState.value));
  }

  // ============================================================================
  // Admin Controls (for testing)
  // ============================================================================

  function startLottery(prizeLevel: string): void {
    if (!socket.value?.connected) return;

    socket.value.emit('draw:start' as any, {
      prizeLevel,
      filters: {},
    }, () => {});
  }

  function stopLottery(): void {
    if (!socket.value?.connected) return;

    socket.value.emit('draw:stop' as any, () => {});
  }

  // ============================================================================
  // Lifecycle
  // ============================================================================

  onMounted(() => {
    connect();
  });

  onUnmounted(() => {
    disconnect();
  });

  return {
    // State (readonly)
    isConnected: readonly(isConnected),
    isConnecting: readonly(isConnecting),
    onlineUsers: readonly(onlineUsers),
    latency: readonly(latency),
    lotteryState: readonly(lotteryState),

    // Methods
    connect,
    disconnect,
    onVoteUpdate,
    onLotteryStateChange,
    startLottery,
    stopLottery,

    // Socket access (for advanced usage)
    getSocket: () => socket.value,
  };
}
