<!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) {
      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 createRoomCard(room) {
      const flagUrl = `${CONSTANTS.FLAG_BASE_URL}${room.country.toLowerCase()}.svg`;
      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>