import { defineStore } from 'pinia';
import { ref, computed, shallowRef, watch } from 'vue';
import { io, Socket } from 'socket.io-client';
import type {
  ServerToClientEvents,
  ClientToServerEvents,
  AdminState,
  SystemPhase,
  VotingControlPayload,
  LotteryControlPayload,
  EmergencyResetPayload,
  MusicControlPayload,
  LotteryRound,
} from '@gala/shared/types';
import { PRIZE_CONFIG } from '@gala/shared/types';
import { SOCKET_EVENTS } from '@gala/shared/constants';

type GalaSocket = Socket<ServerToClientEvents, ClientToServerEvents>;

// Storage key for state persistence
const STORAGE_KEY = 'gala_admin_state';

export const useAdminStore = defineStore('admin', () => {
  // Socket
  const socket = shallowRef<GalaSocket | null>(null);
  const isConnected = ref(false);
  const isConnecting = ref(false);
  const latency = ref(0);
  const onlineUsers = ref(0);

  // Admin State (mirrors server state)
  const systemPhase = ref<SystemPhase>('IDLE');
  const votingOpen = ref(false);
  const votingPaused = ref(false);
  const totalVotes = ref(0);
  const programs = ref<Array<{ id: string; name: string; teamName: string; order: number; status: string; votes: number; stamps: any[] }>>([]);
  const allowLateCatch = ref(true);
  const currentProgramId = ref<string | null>(null);

  // Lottery State
  const lotteryRound = ref<LotteryRound>(1);
  const lotterySubPhase = ref<'IDLE' | 'GALAXY' | 'STORM' | 'REVEAL' | 'COMPLETE'>('IDLE');
  const stormStartedAt = ref<number | null>(null);
  const currentWinners = ref<Array<{ id: string; name: string; department: string }>>([]);

  // Music State
  const musicPlaying = ref(false);
  const musicTrack = ref<'bgm' | 'lottery' | 'fanfare' | 'none'>('none');

  // UI State
  const pendingAction = ref<string | null>(null);
  const lastError = ref<string | null>(null);
  const lastActionTime = ref(0);

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

  const currentPrize = computed(() => {
    const config = PRIZE_CONFIG.find(p => p.round === lotteryRound.value);
    return config || PRIZE_CONFIG[0];
  });

  const canStopLottery = computed(() => {
    if (lotterySubPhase.value !== 'STORM') return false;
    if (!stormStartedAt.value) return false;
    // 3-second safety delay
    return Date.now() - stormStartedAt.value >= 3000;
  });

  const stopButtonCountdown = computed(() => {
    if (lotterySubPhase.value !== 'STORM') return 0;
    if (!stormStartedAt.value) return 3;
    const elapsed = Date.now() - stormStartedAt.value;
    return Math.max(0, Math.ceil((3000 - elapsed) / 1000));
  });

  // Persist state to localStorage
  function saveState() {
    const state = {
      systemPhase: systemPhase.value,
      votingOpen: votingOpen.value,
      votingPaused: votingPaused.value,
      lotteryRound: lotteryRound.value,
      lotterySubPhase: lotterySubPhase.value,
      currentWinners: currentWinners.value,
      musicPlaying: musicPlaying.value,
      musicTrack: musicTrack.value,
    };
    localStorage.setItem(STORAGE_KEY, JSON.stringify(state));
  }

  // Restore state from localStorage
  function restoreState() {
    try {
      const saved = localStorage.getItem(STORAGE_KEY);
      if (saved) {
        const state = JSON.parse(saved);
        systemPhase.value = state.systemPhase || 'IDLE';
        votingOpen.value = state.votingOpen || false;
        votingPaused.value = state.votingPaused || false;
        lotteryRound.value = state.lotteryRound || 1;
        lotterySubPhase.value = state.lotterySubPhase || 'IDLE';
        currentWinners.value = state.currentWinners || [];
        musicPlaying.value = state.musicPlaying || false;
        musicTrack.value = state.musicTrack || 'none';
      }
    } catch (e) {
      console.error('[Admin] Failed to restore state:', e);
    }
  }

  // Watch for state changes and persist
  watch(
    [systemPhase, votingOpen, votingPaused, lotteryRound, lotterySubPhase, currentWinners, musicPlaying, musicTrack],
    () => saveState(),
    { deep: true }
  );

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

    isConnecting.value = true;
    restoreState();

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

    socketInstance.on('connect', () => {
      console.log('[Admin] Connected');
      isConnected.value = true;
      isConnecting.value = false;

      // Join as admin
      socketInstance.emit(SOCKET_EVENTS.CONNECTION_JOIN as any, {
        userId: 'admin_main',
        userName: 'Admin Console',
        role: 'admin',
      }, () => { });

      // Request state sync
      socketInstance.emit(SOCKET_EVENTS.ADMIN_STATE_SYNC as any, {});
    });

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

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

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

    // Admin state sync from server
    socketInstance.on(SOCKET_EVENTS.ADMIN_STATE_SYNC as any, (state: AdminState) => {
      syncFromServer(state);
    });

    socket.value = socketInstance as GalaSocket;
  }

  function syncFromServer(state: AdminState) {
    systemPhase.value = state.systemPhase;
    votingOpen.value = state.voting.subPhase === 'OPEN';
    votingPaused.value = state.voting.subPhase === 'PAUSED';
    totalVotes.value = state.voting.totalVotes;
    programs.value = state.voting.programs || [];
    allowLateCatch.value = state.voting.allowLateCatch ?? true;
    currentProgramId.value = state.voting.currentProgramId || null;
    lotteryRound.value = state.lottery.round;
    lotterySubPhase.value = state.lottery.subPhase;
    currentWinners.value = state.lottery.currentWinners;
    musicPlaying.value = state.music.isPlaying;
    musicTrack.value = state.music.track;
    saveState();
  }

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

  // Admin Actions
  function setPhase(phase: SystemPhase) {
    if (!socket.value?.connected) return;
    pendingAction.value = 'phase_change';

    socket.value.emit(SOCKET_EVENTS.ADMIN_PHASE_CHANGE as any, {
      phase,
      timestamp: Date.now(),
    }, (response: any) => {
      pendingAction.value = null;
      if (response.success) {
        systemPhase.value = phase;
        lastActionTime.value = Date.now();
      } else {
        lastError.value = response.message || 'Failed to change phase';
      }
    });
  }

  function controlVoting(action: 'open' | 'close' | 'pause' | 'resume') {
    if (!socket.value?.connected) return;
    pendingAction.value = `voting_${action}`;

    socket.value.emit(SOCKET_EVENTS.ADMIN_VOTING_CONTROL as any, {
      action,
      timestamp: Date.now(),
    } as VotingControlPayload, (response: any) => {
      pendingAction.value = null;
      if (response.success) {
        if (action === 'open') {
          votingOpen.value = true;
          votingPaused.value = false;
        } else if (action === 'close') {
          votingOpen.value = false;
          votingPaused.value = false;
        } else if (action === 'pause') {
          votingPaused.value = true;
        } else if (action === 'resume') {
          votingPaused.value = false;
        }
        lastActionTime.value = Date.now();
      } else {
        lastError.value = response.message || `Failed to ${action} voting`;
      }
    });
  }

  function controlLottery(action: LotteryControlPayload['action'], winnerIds?: string[]) {
    if (!socket.value?.connected) return;
    pendingAction.value = `lottery_${action}`;

    const payload: LotteryControlPayload = {
      action,
      round: lotteryRound.value,
      timestamp: Date.now(),
    };
    if (winnerIds) payload.winnerIds = winnerIds;

    socket.value.emit(SOCKET_EVENTS.ADMIN_LOTTERY_CONTROL as any, payload, (response: any) => {
      pendingAction.value = null;
      if (response.success) {
        if (action === 'start_galaxy') {
          lotterySubPhase.value = 'GALAXY';
        } else if (action === 'start_storm') {
          lotterySubPhase.value = 'STORM';
          stormStartedAt.value = Date.now();
        } else if (action === 'stop_reveal') {
          lotterySubPhase.value = 'REVEAL';
          if (response.data?.winners) {
            currentWinners.value = response.data.winners;
          }
        } else if (action === 'next_round') {
          lotteryRound.value = Math.min(4, lotteryRound.value + 1) as LotteryRound;
          lotterySubPhase.value = 'IDLE';
          currentWinners.value = [];
          stormStartedAt.value = null;
        } else if (action === 'reset') {
          lotteryRound.value = 1;
          lotterySubPhase.value = 'IDLE';
          currentWinners.value = [];
          stormStartedAt.value = null;
        }
        lastActionTime.value = Date.now();
      } else {
        lastError.value = response.message || `Failed to ${action}`;
      }
    });
  }

  function emergencyReset(scope: 'all' | 'voting' | 'lottery', confirmCode: string) {
    if (!socket.value?.connected) return;
    if (confirmCode !== 'RESET') {
      lastError.value = 'Invalid confirmation code';
      return;
    }
    pendingAction.value = 'emergency_reset';

    socket.value.emit(SOCKET_EVENTS.ADMIN_EMERGENCY_RESET as any, {
      scope,
      confirmCode,
      timestamp: Date.now(),
    } as EmergencyResetPayload, (response: any) => {
      pendingAction.value = null;
      if (response.success) {
        if (scope === 'all' || scope === 'voting') {
          votingOpen.value = false;
          votingPaused.value = false;
          totalVotes.value = 0;
        }
        if (scope === 'all' || scope === 'lottery') {
          lotteryRound.value = 1;
          lotterySubPhase.value = 'IDLE';
          currentWinners.value = [];
          stormStartedAt.value = null;
        }
        if (scope === 'all') {
          systemPhase.value = 'IDLE';
        }
        lastActionTime.value = Date.now();
      } else {
        lastError.value = response.message || 'Emergency reset failed';
      }
    });
  }

  function controlMusic(action: 'play' | 'stop' | 'change_track', track?: MusicControlPayload['track']) {
    if (!socket.value?.connected) return;
    pendingAction.value = `music_${action}`;

    socket.value.emit(SOCKET_EVENTS.ADMIN_MUSIC_CONTROL as any, {
      action,
      track,
    } as MusicControlPayload, (response: any) => {
      pendingAction.value = null;
      if (response.success) {
        if (action === 'play') {
          musicPlaying.value = true;
          if (track) musicTrack.value = track;
        } else if (action === 'stop') {
          musicPlaying.value = false;
        } else if (action === 'change_track' && track) {
          musicTrack.value = track;
        }
        lastActionTime.value = Date.now();
      } else {
        lastError.value = response.message || `Failed to ${action} music`;
      }
    });
  }

  function clearError() {
    lastError.value = null;
  }

  return {
    // Connection
    isConnected,
    isConnecting,
    connectionStatus,
    latency,
    onlineUsers,

    // State
    systemPhase,
    votingOpen,
    votingPaused,
    totalVotes,
    programs,
    allowLateCatch,
    currentProgramId,
    lotteryRound,
    lotterySubPhase,
    stormStartedAt,
    currentWinners,
    musicPlaying,
    musicTrack,

    // Computed
    currentPrize,
    canStopLottery,
    stopButtonCountdown,

    // UI State
    pendingAction,
    lastError,
    lastActionTime,

    // Actions
    connect,
    disconnect,
    setPhase,
    controlVoting,
    controlLottery,
    emergencyReset,
    controlMusic,
    clearError,
    getSocket: () => socket.value,
  };
});
