<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  <title>HaxBall Rooms Dashboard</title>
  <style>
    :root {
      --primary: #2563eb;
      --background: #f8fafc;
      --card: #ffffff;
      --text: #1e293b;
      --border: #e2e8f0;
    }

    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
      font-family: system-ui, -apple-system, sans-serif;
    }

    body {
      background: var(--background);
      color: var(--text);
      padding: 2rem 1rem;
    }

    .container {
      max-width: 1200px;
      margin: 0 auto;
    }

    .header {
      margin-bottom: 2rem;
      text-align: center;
    }

    .controls {
      display: flex;
      gap: 1rem;
      flex-wrap: wrap;
      margin-bottom: 2rem;
      justify-content: center;
    }

    select,
    input {
      padding: 0.5rem;
      border: 1px solid var(--border);
      border-radius: 0.375rem;
      background: var(--card);
      min-width: 200px;
    }

    .grid {
      display: grid;
      grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
      gap: 1rem;
    }

    .card {
      background: var(--card);
      border: 1px solid var(--border);
      border-radius: 0.5rem;
      padding: 1rem;
      transition: transform 0.2s;
    }

    .card:hover {
      transform: translateY(-2px);
    }

    .card h3 {
      margin-bottom: 0.5rem;
      font-size: 1rem;
      line-height: 1.4;
      word-break: break-word;
    }

    .card-stats {
      display: flex;
      gap: 1rem;
      margin-top: 1rem;
      font-size: 0.875rem;
      align-items: center;
      flex-wrap: wrap;
    }

    .card-stat {
      display: flex;
      align-items: center;
      gap: 0.25rem;
    }

    .flag {
      width: 1.5rem;
      height: 1rem;
      border-radius: 0.125rem;
      object-fit: cover;
    }

    .loading {
      text-align: center;
      padding: 2rem;
      font-size: 1.25rem;
    }

    .error {
      text-align: center;
      padding: 2rem;
      color: #dc2626;
    }

    .button {
      padding: 0.5rem 1rem;
      background: var(--primary);
      color: white;
      border: none;
      border-radius: 0.375rem;
      cursor: pointer;
      transition: opacity 0.2s;
      text-decoration: none;
      font-size: 0.875rem;
    }

    .button:hover {
      opacity: 0.9;
    }

    .country-info {
      display: flex;
      align-items: center;
      gap: 0.5rem;
    }

    .stats {
      margin-bottom: 1rem;
      text-align: center;
      color: var(--text);
      opacity: 0.8;
    }

    .map-container {
      transition: all 0.3s ease;
      overflow: hidden;
    }

    .map-container.active {
      display: block !important;
    }

    .show-map-btn {
      background: #4b5563;
    }

    .show-map-btn.active {
      background: #1f2937;
    }

    .map-controls {
      display: flex;
      gap: 0.5rem;
      margin-bottom: 0.5rem;
      flex-wrap: wrap;
    }

    .map-controls select,
    .map-controls input {
      min-width: auto;
      font-size: 0.75rem;
      padding: 0.25rem 0.5rem;
    }

    .coordinates {
      font-size: 0.875rem;
      color: #666;
      margin-bottom: 0.5rem;
    }

    @media (max-width: 640px) {
      .controls {
        flex-direction: column;
        align-items: stretch;
      }

      select,
      input {
        width: 100%;
        min-width: 0;
      }

      .map-controls {
        flex-direction: column;
      }
    }
  </style>
</head>

<body>
  <div class="container">
    <div class="header">
      <h1>HaxBall Rooms</h1>
    </div>

    <div class="controls">
      <input type="text" id="search" placeholder="Search rooms...">
      <select id="country">
        <option value="">All Countries</option>
      </select>
      <select id="sort">
        <option value="players-desc">Most Players</option>
        <option value="players-asc">Least Players</option>
        <option value="name-asc">Name (A-Z)</option>
        <option value="name-desc">Name (Z-A)</option>
        <option value="capacity-desc">Most Capacity</option>
        <option value="capacity-asc">Least Capacity</option>
      </select>
      <button class="button" id="refresh">Refresh</button>
    </div>

    <div id="stats" class="stats"></div>
    <div id="rooms" class="grid">
      <div class="loading">Loading rooms...</div>
    </div>
  </div>

  <script>
    const GOOGLE_MAPS_API_KEY = "AIzaSyBmyUM-Qm7b6M-eeEWd5j-JP2VgjOqQlxc";

    function cleanRoomName(name) {
      return name
        .replace(/�/g, '')
        .replace(/[\uFFFD]/g, '')
        .trim()
        .replace(/\s+/g, ' ');
    }

    const CONSTANTS = {
      API_URL: 'https://api.sefinek.net/api/v2/haxball/room-list',
      FLAG_BASE_URL: 'https://raw.githubusercontent.com/hampusborgos/country-flags/main/svg/',
      COUNTRIES_URL: 'https://raw.githubusercontent.com/hampusborgos/country-flags/main/countries.json',
      FALLBACK_FLAG: 'https://upload.wikimedia.org/wikipedia/commons/5/5a/Black_question_mark.png'
    };

    const workerScript = `
      const API_URL = '${CONSTANTS.API_URL}';
      const FLAG_BASE_URL = '${CONSTANTS.FLAG_BASE_URL}';
      const COUNTRIES_URL = '${CONSTANTS.COUNTRIES_URL}';
      let countryNames = {};
      let allRooms = [];

      function cleanRoomName(name) {
          return name
              .replace(/�/g, '')
              .replace(/[\uFFFD]/g, '')
              .trim()
              .replace(/\s+/g, ' ');
      }

      async function initializeCountryNames() {
          try {
              const response = await fetch(COUNTRIES_URL);
              countryNames = await response.json();
              return countryNames;
          } catch (error) {
              console.error('Error loading country names:', error);
              return {};
          }
      }

      async function fetchRooms() {
          try {
              const response = await fetch(API_URL);
              if (!response.ok) throw new Error('Failed to fetch rooms');
              const data = await response.json();
              
              data.rooms = data.rooms.map(room => ({
                  ...room,
                  name: cleanRoomName(room.name)
              }));
              
              return data.rooms;
          } catch (error) {
              throw error;
          }
      }

      function filterAndSortRooms(searchTerm, country, sortValue) {
          let filteredRooms = allRooms.filter(room => {
              const cleanedSearch = cleanRoomName(searchTerm.toLowerCase());
              const cleanedName = cleanRoomName(room.name.toLowerCase());
              const matchesSearch = cleanedName.includes(cleanedSearch);
              const matchesCountry = !country || room.country === country;
              return matchesSearch && matchesCountry;
          });

          const [sortKey, sortOrder] = sortValue.split('-');
          filteredRooms.sort((a, b) => {
              let comparison;
              switch (sortKey) {
                  case 'players':
                      comparison = a.players - b.players;
                      break;
                  case 'name':
                      comparison = cleanRoomName(a.name).localeCompare(cleanRoomName(b.name));
                      break;
                  case 'capacity':
                      comparison = a.maxPlayers - b.maxPlayers;
                      break;
                  default:
                      comparison = 0;
              }
              return sortOrder === 'desc' ? -comparison : comparison;
          });

          return filteredRooms;
      }

      self.onmessage = async function(e) {
          const { type, data } = e.data;

          switch (type) {
              case 'init':
                  try {
                      const [rooms, names] = await Promise.all([
                          fetchRooms(),
                          initializeCountryNames()
                      ]);
                      allRooms = rooms;
                      countryNames = names;
                      self.postMessage({ 
                          type: 'initialized', 
                          rooms: allRooms, 
                          countryNames: countryNames 
                      });
                  } catch (error) {
                      self.postMessage({ type: 'error', error: error.message });
                  }
                  break;

              case 'filter':
                  const { searchTerm, country, sortValue } = data;
                  const filteredRooms = filterAndSortRooms(searchTerm, country, sortValue);
                  self.postMessage({ 
                      type: 'filtered', 
                      rooms: filteredRooms,
                      countryNames: countryNames
                  });
                  break;

              case 'refresh':
                  try {
                      allRooms = await fetchRooms();
                      self.postMessage({ 
                          type: 'refreshed', 
                          rooms: allRooms,
                          countryNames: countryNames
                      });
                  } catch (error) {
                      self.postMessage({ type: 'error', error: error.message });
                  }
                  break;
          }
      };
    `;

    const workerBlob = new Blob([workerScript], {type: 'application/javascript'});
    const workerUrl = URL.createObjectURL(workerBlob);
    const worker = new Worker(workerUrl);

    let countryNames = {};
    let allRooms = [];
    let debounceTimeout;

    function debounce(func, wait) {
      return function executedFunction(...args) {
        const later = () => {
          clearTimeout(debounceTimeout);
          func(...args);
        };
        clearTimeout(debounceTimeout);
        debounceTimeout = setTimeout(later, wait);
      };
    }

    function updateCountrySelect(rooms) {
      const countries = [...new Set(rooms.map(room => room.country))].sort();
      const select = document.getElementById('country');
      select.innerHTML = '<option value="">All Countries</option>';
      countries.forEach(country => {
        const option = document.createElement('option');
        option.value = country;
        const countryName = countryNames[country.toUpperCase()] || country.toUpperCase();
        option.textContent = countryName;
        select.appendChild(option);
      });
    }

    function getCountryName(countryCode) {
      if (!countryCode) return 'Unknown';
      return countryNames[countryCode.toUpperCase()] || countryCode.toUpperCase();
    }

    function getCustomFlagUrl(countryCode) {
      countryCode = countryCode.toLowerCase();
      switch (countryCode) {
        case 'eng':
          return `${CONSTANTS.FLAG_BASE_URL}gb-eng.svg`;
        case 'uk':
          return `${CONSTANTS.FLAG_BASE_URL}gb.svg`;
        case 'un':
          return 'https://upload.wikimedia.org/wikipedia/commons/2/2f/Flag_of_the_United_Nations.svg';
        default:
          return `${CONSTANTS.FLAG_BASE_URL}${countryCode}.svg`;
      }
    }

    function toggleMap(roomId) {
      const mapContainer = document.getElementById(`map-${roomId}`);
      const button = mapContainer.parentElement.querySelector('.show-map-btn');

      if (mapContainer.style.display === 'none') {
        mapContainer.style.display = 'block';
        button.textContent = 'Hide Map';
        button.classList.add('active');
      } else {
        mapContainer.style.display = 'none';
        button.textContent = 'Show Map';
        button.classList.remove('active');
      }
    }

    function createRoomCard(room) {
      const flagUrl = getCustomFlagUrl(room.country);
      const countryName = getCountryName(room.country);
      const cleanedName = cleanRoomName(room.name);

      return `
        <div class="card">
            <h3 dir="auto">${cleanedName}</h3>
            <div class="card-stats">
                <div class="country-info">
                    <img class="flag" src="${flagUrl}" 
                         alt="${countryName}" 
                         onerror="this.src='${CONSTANTS.FALLBACK_FLAG}'">
                    <span>${countryName}</span>
                </div>
                <div class="card-stat">
                    👥 ${room.players}/${room.maxPlayers}
                </div>
                <div class="card-stat">
                    ${room.password ? '🔒' : '🔓'}
                </div>
                <button class="button show-map-btn" onclick="toggleMap('${room.id}')">Show Map</button>
                <a href="${room.url}" target="_blank" class="button">Join</a>
            </div>
            <div id="map-${room.id}" class="map-container" style="display: none; margin-top: 1rem;">
                <div class="coordinates">
                    📍 Latitude: ${room.lat.toFixed(4)}, Longitude: ${room.lon.toFixed(4)}
                </div>
                <div class="map-controls">
                    <select id="zoom-${room.id}" onchange="updateMap('${room.id}')">
                        <option value="8">Zoom: 8x</option>
                        <option value="10">Zoom: 10x</option>
                        <option value="12" selected>Zoom: 12x</option>
                        <option value="14">Zoom: 14x</option>
                        <option value="16">Zoom: 16x</option>
                    </select>
                    <select id="size-${room.id}" onchange="updateMap('${room.id}')">
                        <option value="400x200" selected>Size: Normal</option>
                        <option value="600x300">Size: Large</option>
                        <option value="800x400">Size: Extra Large</option>
                    </select>
                    <select id="type-${room.id}" onchange="updateMap('${room.id}')">
                        <option value="roadmap" selected>Map: Road</option>
                        <option value="satellite">Map: Satellite</option>
                        <option value="hybrid">Map: Hybrid</option>
                        <option value="terrain">Map: Terrain</option>
                    </select>
                </div>
                <img id="map-img-${room.id}"
                     src="https://maps.googleapis.com/maps/api/staticmap?center=${room.lat},${room.lon}&zoom=12&size=400x200&maptype=roadmap&markers=color:red%7C${room.lat},${room.lon}&key=${GOOGLE_MAPS_API_KEY}" 
                     alt="Location map" 
                     style="width: 100%; border-radius: 0.375rem;">
            </div>
        </div>
    `;
    }

    function updateMap(roomId) {
      const zoom = document.getElementById(`zoom-${roomId}`).value;
      const size = document.getElementById(`size-${roomId}`).value;
      const mapType = document.getElementById(`type-${roomId}`).value;

      // Find the room data
      const room = allRooms.find(r => r.id === roomId);
      if (!room) return;

      // Update the map image
      const mapImg = document.getElementById(`map-img-${roomId}`);
      const newUrl = `https://maps.googleapis.com/maps/api/staticmap?center=${room.lat},${room.lon}&zoom=${zoom}&size=${size}&maptype=${mapType}&markers=color:red%7C${room.lat},${room.lon}&key=${GOOGLE_MAPS_API_KEY}`;
      mapImg.src = newUrl;
    }

    function updateStats(filteredRooms) {
      const totalRooms = filteredRooms.length;
      const totalPlayers = filteredRooms.reduce((sum, room) => sum + room.players, 0);
      const totalCapacity = filteredRooms.reduce((sum, room) => sum + room.maxPlayers, 0);

      document.getElementById('stats').innerHTML = `
        Showing ${totalRooms} room${totalRooms !== 1 ? 's' : ''} | 
${totalPlayers} player${totalPlayers !== 1 ? 's' : ''} online | 
        Total capacity: ${totalCapacity}
      `;
    }

    function requestFilteredRooms() {
      const searchTerm = document.getElementById('search').value;
      const country = document.getElementById('country').value;
      const sortValue = document.getElementById('sort').value;

      worker.postMessage({
        type: 'filter',
        data: {searchTerm, country, sortValue}
      });
    }

    worker.onmessage = function (e) {
      const {type, rooms, countryNamesData, error} = e.data;

      switch (type) {
        case 'initialized':
          allRooms = rooms;
          countryNames = e.data.countryNames;
          updateCountrySelect(rooms);
          requestFilteredRooms();
          break;

        case 'filtered':
          const roomsContainer = document.getElementById('rooms');
          countryNames = e.data.countryNames;
          updateStats(rooms);
          roomsContainer.innerHTML = rooms.map(createRoomCard).join('');
          break;

        case 'refreshed':
          allRooms = rooms;
          countryNames = e.data.countryNames;
          updateCountrySelect(rooms);
          requestFilteredRooms();
          break;

        case 'error':
          document.getElementById('rooms').innerHTML =
            `<div class="error">Failed to load rooms: ${error}</div>`;
          break;
      }
    };

    document.getElementById('search').addEventListener('input',
      debounce(requestFilteredRooms, 300));
    document.getElementById('country').addEventListener('change', requestFilteredRooms);
    document.getElementById('sort').addEventListener('change', requestFilteredRooms);
    document.getElementById('refresh').addEventListener('click', () => {
      worker.postMessage({type: 'refresh'});
    });

    worker.postMessage({type: 'init'});

    window.addEventListener('beforeunload', () => {
      worker.terminate();
      URL.revokeObjectURL(workerUrl);
    });
  </script>
</body>

</html>