var LudoLive = (function() {
  'use strict';

  var C = LudoConstants;
  var UI = LudoUI;
  var Chat = LudoChat;

  var state = {
    matchId: null,
    userId: null,
    token: null,
    match: null,
    myColor: null,
    connected: false,
    reconnecting: false
  };

  var LUDO_RT_ENDPOINT = 'wss://safe-supabase-kong.caprover.al-arcade.com/realtime/v1/websocket';
  var ANON_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImlzcyI6InN1cGFiYXNlIiwiaWF0IjoxNzM1Njg5NjAwLCJleHAiOjE4OTM0NTYwMDB9.31PF6PvP-pSrvRuQwLFptQoejR0W1A7o53lZhEbnz84';

  var ws = null;
  var topic = null;
  var heartbeatInterval = null;
  var heartbeatRef = 0;
  var awaitingHeartbeat = false;
  var reconnectAttempts = 0;
  var reconnectTimer = null;

  function init(options) {
    state.matchId = options.matchId;
    state.userId = options.userId;
    state.token = options.token;

    connect();
    fetchState();
  }

  function connect() {
    if (ws) { ws.onclose = null; ws.close(); }

    var url = LUDO_RT_ENDPOINT + '?apikey=' + ANON_KEY + '&vsn=1.0.0';
    ws = new WebSocket(url);

    ws.onopen = function() {
      state.connected = true;
      state.reconnecting = false;
      reconnectAttempts = 0;
      startHeartbeat();
      joinChannel();
    };

    ws.onmessage = function(evt) {
      handleMessage(evt);
    };

    ws.onclose = function() {
      state.connected = false;
      stopHeartbeat();
      scheduleReconnect();
    };

    ws.onerror = function() {};
  }

  function joinChannel() {
    topic = 'realtime:public:ludo_matches:id=eq.' + state.matchId;
    send({
      topic: topic,
      event: 'phx_join',
      payload: {
        config: {
          broadcast: { self: false },
          presence: { key: '' },
          postgres_changes: [{
            event: 'UPDATE',
            schema: 'public',
            table: 'ludo_matches',
            filter: 'id=eq.' + state.matchId
          }]
        },
        access_token: state.token
      },
      ref: '1'
    });
  }

  function handleMessage(evt) {
    var msg;
    try { msg = JSON.parse(evt.data); } catch(e) { return; }

    if (msg.topic === 'phoenix' && msg.event === 'phx_reply') {
      awaitingHeartbeat = false;
      return;
    }

    if (msg.event === 'postgres_changes' && msg.topic === topic) {
      var payload = msg.payload;
      if (payload && payload.data && payload.data.type === 'UPDATE' && payload.data.record) {
        onMatchUpdate(payload.data.record);
      }
    }
  }

  function startHeartbeat() {
    stopHeartbeat();
    heartbeatInterval = setInterval(function() {
      if (awaitingHeartbeat) { ws.close(); return; }
      awaitingHeartbeat = true;
      heartbeatRef++;
      send({ topic: 'phoenix', event: 'heartbeat', payload: {}, ref: String(heartbeatRef) });
    }, 30000);
  }

  function stopHeartbeat() {
    if (heartbeatInterval) { clearInterval(heartbeatInterval); heartbeatInterval = null; }
    awaitingHeartbeat = false;
  }

  function scheduleReconnect() {
    if (reconnectAttempts >= 10) return;
    var delay = Math.min(1000 * Math.pow(2, reconnectAttempts), 30000);
    reconnectAttempts++;
    state.reconnecting = true;
    reconnectTimer = setTimeout(function() { connect(); }, delay);
  }

  function send(msg) {
    if (ws && ws.readyState === WebSocket.OPEN) {
      ws.send(JSON.stringify(msg));
    }
  }

  function fetchState() {
    apiCall('GET', '/api/ludo?action=status&match_id=' + state.matchId, null, function(data) {
      if (data.ok) {
        onMatchUpdate(data.match);
      }
    });
  }

  function onMatchUpdate(match) {
    state.match = match;

    var players = typeof match.players === 'string' ? JSON.parse(match.players) : match.players;
    var positions = typeof match.positions === 'string' ? JSON.parse(match.positions) : match.positions;
    var winners = typeof match.winners === 'string' ? JSON.parse(match.winners) : match.winners;
    var gameState = typeof match.game_state === 'string' ? JSON.parse(match.game_state) : match.game_state;
    var chat = typeof match.chat === 'string' ? JSON.parse(match.chat) : match.chat;

    // Determine my color
    for (var i = 0; i < players.length; i++) {
      if (players[i].id === state.userId) {
        state.myColor = players[i].color;
        break;
      }
    }

    var activePlayers = players.map(function(p) { return p.color; });
    var playerNames = {};
    players.forEach(function(p) { playerNames[p.color] = p.name; });

    // Render board if not yet rendered
    if (!document.querySelector('.ludo-board')) {
      UI.renderBoard('#ludo-board');
      UI.renderDice('#ludo-dice-container');
      UI.setTurnElement(document.getElementById('ludo-turn'));
      UI.setLogElement(document.getElementById('ludo-log'));
      UI.renderPlayerCards(
        document.getElementById('ludo-top-players'),
        document.getElementById('ludo-bottom-players'),
        activePlayers,
        playerNames
      );
      UI.renderPieces(activePlayers);

      Chat.init('#ludo-chat', state.matchId, function(text) {
        apiCall('POST', '/api/ludo', { action: 'chat', match_id: state.matchId, text: text });
      });
    }

    // Update all piece positions
    activePlayers.forEach(function(p) {
      if (!positions[p]) return;
      for (var i = 0; i < 4; i++) {
        UI.setPiecePosition(p, i, positions[p][i]);
      }
    });
    UI.updateStacking(positions, activePlayers);

    // Update turn
    var currentPlayer = players[match.current_turn];
    if (currentPlayer) {
      UI.setTurn(currentPlayer.color, currentPlayer.name);
    }

    // Update dice
    if (match.dice_value) {
      UI.setDiceValue(match.dice_value);
    }

    // Update winners
    winners.forEach(function(w) { UI.setPlayerFinished(w); });

    // Update chat
    if (chat && chat.length > 0) {
      Chat.loadMessages(chat);
    }

    // Handle game state
    if (match.status === 'completed') {
      var winnerColor = winners[0] || '';
      var winnerName = playerNames[winnerColor] || winnerColor;
      var isWinner = winnerColor === state.myColor;
      UI.showResult(
        isWinner ? 'فزت!' : winnerName + ' فاز!',
        'ترتيب: ' + winners.map(function(w, i) { return (i+1) + '. ' + (playerNames[w] || w); }).join(' | ')
      );
      UI.disableDice();
      return;
    }

    // Enable/disable dice based on turn
    if (currentPlayer && currentPlayer.id === state.userId && gameState.phase === 'dice_not_rolled') {
      UI.enableDice();
      UI.unhighlightPieces();
    } else if (currentPlayer && currentPlayer.id === state.userId && gameState.phase === 'dice_rolled') {
      UI.disableDice();
      highlightEligible(currentPlayer.color, match.dice_value, positions, activePlayers);
    } else {
      UI.disableDice();
      UI.unhighlightPieces();
    }
  }

  function highlightEligible(playerColor, diceValue, positions, activePlayers) {
    var eligible = LudoBot.getEligiblePieces(playerColor, diceValue, positions, activePlayers);
    if (eligible.length === 0) {
      // No moves, auto-skip
      skipTurn();
      return;
    }
    UI.highlightPieces(playerColor, eligible);
  }

  function onDiceClick() {
    if (!state.match) return;
    var players = typeof state.match.players === 'string' ? JSON.parse(state.match.players) : state.match.players;
    var currentPlayer = players[state.match.current_turn];
    if (!currentPlayer || currentPlayer.id !== state.userId) return;

    var gameState = typeof state.match.game_state === 'string' ? JSON.parse(state.match.game_state) : state.match.game_state;
    if (gameState.phase !== 'dice_not_rolled') return;

    UI.disableDice();
    apiCall('POST', '/api/ludo', { action: 'roll', match_id: state.matchId }, function(data) {
      if (data.ok && data.dice_value) {
        UI.animateDiceRoll(data.dice_value, function() {});
      }
    });
  }

  function onPieceClick(e) {
    var target = e.target.closest('.ludo-piece--highlight');
    if (!target) return;

    var player = target.dataset.player;
    var pieceIdx = parseInt(target.dataset.piece, 10);

    if (player !== state.myColor) return;

    UI.unhighlightPieces();
    UI.disableDice();

    apiCall('POST', '/api/ludo', {
      action: 'move',
      match_id: state.matchId,
      piece: pieceIdx
    });
  }

  function skipTurn() {
    apiCall('POST', '/api/ludo', {
      action: 'move',
      match_id: state.matchId,
      piece: -1
    });
  }

  function leave() {
    apiCall('POST', '/api/ludo', { action: 'leave', match_id: state.matchId });
    if (ws) { ws.onclose = null; ws.close(); }
    stopHeartbeat();
  }

  function bindUI() {
    UI.listenDiceClick(onDiceClick);
    UI.listenPieceClick(onPieceClick);
  }

  function apiCall(method, url, data, callback) {
    var xhr = new XMLHttpRequest();
    xhr.open(method, url, true);
    xhr.setRequestHeader('Content-Type', 'application/json');
    if (state.token) {
      xhr.setRequestHeader('Authorization', 'Bearer ' + state.token);
    }
    xhr.onload = function() {
      if (callback) {
        try { callback(JSON.parse(xhr.responseText)); }
        catch(e) { callback({ error: 'parse_error' }); }
      }
    };
    xhr.onerror = function() {
      if (callback) callback({ error: 'network_error' });
    };
    xhr.send(data ? JSON.stringify(data) : null);
  }

  function createRoom(playerCount, bots, callback) {
    apiCall('POST', '/api/ludo', {
      action: 'create',
      player_count: playerCount,
      bots: bots || []
    }, callback);
  }

  function joinRoom(roomCode, callback) {
    apiCall('POST', '/api/ludo', {
      action: 'join',
      room_code: roomCode
    }, callback);
  }

  function startGame(callback) {
    apiCall('POST', '/api/ludo', {
      action: 'start',
      match_id: state.matchId
    }, callback);
  }

  function setAuth(token, userId) {
    state.token = token;
    state.userId = userId;
  }

  return {
    init: init,
    setAuth: setAuth,
    bindUI: bindUI,
    fetchState: fetchState,
    leave: leave,
    createRoom: createRoom,
    joinRoom: joinRoom,
    startGame: startGame,
    getState: function() { return state; }
  };
})();
