<!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;
    }

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

      select,
      input {
        width: 100%;
        min-width: 0;
      }
    }
  </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>
    function cleanRoomName(name) {
      console.log('Original name:', name); // Debugging: Log the original name
      const cleanedName = name
        .replace(/�/g, '') // Remove the replacement character
        .replace(/[\uFFFD]/g, '') // Remove the Unicode replacement character
        .trim() // Trim leading and trailing whitespace
        .replace(/\s+/g, ' '); // Normalize multiple spaces to a single space
      console.log('Cleaned name:', cleanedName); // Debugging: Log the cleaned name
      return cleanedName;
    }

    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();
          console.log('Raw data from API:', data); // Debugging: Log the raw data
          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 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>
            <a href="${room.url}" target="_blank" class="button">Join</a>
          </div>
        </div>
      `;
    }

    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>