import React, { useEffect, useMemo, useState } from 'react';
import { api } from '../api.js';
import {
  autoServer,
  filterServers,
  groupServers,
  SERVER_RESULT_WINDOW,
} from '../utils/serverPicker.js';

const FAVORITES_KEY = 'harbor-server-favorites';
const RECENT_KEY = 'harbor-server-recent';
const AUTO_KEY = 'harbor-server-auto';

function readList(key) {
  try {
    const value = JSON.parse(localStorage.getItem(key) || '[]');
    return Array.isArray(value) ? value.map(String) : [];
  } catch {
    return [];
  }
}

function write(key, value) {
  try {
    localStorage.setItem(key, typeof value === 'string' ? value : JSON.stringify(value));
  } catch {
    // Preferences remain available for this session.
  }
}

function readAuto() {
  try {
    return localStorage.getItem(AUTO_KEY) === 'true';
  } catch {
    return false;
  }
}

function ServerRow({ server, selected, favorite, ping, disabled, index, onSelect, onFavorite }) {
  const health = ping?.checking
    ? 'Проверяем TCP…'
    : ping?.error ? 'Проверка недоступна'
      : ping?.ok ? `TCP ${ping.latency} мс` : ping ? 'TCP недоступен' : 'Не проверен';

  return <div className={`client-server-row${selected ? ' is-selected' : ''}${onFavorite ? ' has-favorite' : ''}`}>
    <button
      className={`client-server${selected ? ' is-selected' : ''}`}
      type="button"
      disabled={disabled}
      aria-pressed={selected}
      aria-label={`${server.label}, ${server.host}:${server.port}, ${health}`}
      style={{ '--server-index': Math.min(index, 7) }}
      onClick={() => onSelect(server.id)}
    >
      <strong>{server.label}</strong>
      <small title={ping?.checkedAt || undefined}>{health}</small>
    </button>
    {onFavorite && <button
      className={`client-server-favorite${favorite ? ' is-active' : ''}`}
      type="button"
      aria-pressed={favorite}
      aria-label={`${favorite ? 'Убрать из избранного' : 'Добавить в избранное'}: ${server.label}`}
      onClick={() => onFavorite(server.id)}
    >★</button>}
  </div>;
}

export function ServerPicker({
  servers,
  selectedServerId,
  disabled,
  prompt,
  leaving,
  revealVersion,
  onSelect,
}) {
  const [query, setQuery] = useState('');
  const [view, setView] = useState('all');
  const [page, setPage] = useState(0);
  const [favorites, setFavorites] = useState(() => readList(FAVORITES_KEY));
  const [recent, setRecent] = useState(() => readList(RECENT_KEY));
  const [autoActive, setAutoActive] = useState(readAuto);
  const [collapsed, setCollapsed] = useState([]);
  const [pings, setPings] = useState({});
  const [checking, setChecking] = useState(false);
  const serverKey = servers.map(({ id }) => id).join('|');

  useEffect(() => {
    setPage(0);
  }, [query, view, serverKey]);

  const selected = servers.find(({ id }) => id === selectedServerId);
  const filtered = useMemo(() => {
    const found = filterServers(servers, query);
    if (view === 'favorites') return found.filter(({ id }) => favorites.includes(id));
    if (view === 'recent') return recent.flatMap((id) => found.find((server) => server.id === id) || []);
    return found;
  }, [servers, query, view, favorites, recent]);
  const results = filtered.filter(({ id }) => id !== selectedServerId);
  const pageCount = Math.max(1, Math.ceil(results.length / SERVER_RESULT_WINDOW));
  const visible = results.slice(page * SERVER_RESULT_WINDOW, (page + 1) * SERVER_RESULT_WINDOW);
  const grouped = servers.length >= 10;

  useEffect(() => {
    setPage((current) => Math.min(current, pageCount - 1));
  }, [pageCount]);

  function toggleFavorite(id) {
    setFavorites((current) => {
      const next = current.includes(id) ? current.filter((item) => item !== id) : [id, ...current];
      write(FAVORITES_KEY, next);
      return next;
    });
  }

  function select(id, automatic = false) {
    setAutoActive(automatic);
    write(AUTO_KEY, String(automatic));
    if (!automatic) {
      setRecent((current) => {
        const next = [id, ...current.filter((item) => item !== id)].slice(0, 5);
        write(RECENT_KEY, next);
        return next;
      });
    }
    onSelect(id);
  }

  async function checkVisible() {
    const ids = [...new Set([selectedServerId, ...visible.map(({ id }) => id)].filter(Boolean))].slice(0, 30);
    if (!ids.length) return;
    setChecking(true);
    setPings((current) => ({
      ...current,
      ...Object.fromEntries(ids.map((id) => [id, { checking: true }])),
    }));
    try {
      const data = await api.servers.ping(ids);
      setPings((current) => ({
        ...current,
        ...Object.fromEntries((data.results || []).map((result) => [result.id, result])),
      }));
    } catch {
      setPings((current) => ({
        ...current,
        ...Object.fromEntries(ids.map((id) => [id, { error: true, checkedAt: new Date().toISOString() }])),
      }));
    } finally {
      setChecking(false);
    }
  }

  if (servers.length === 1) {
    return <section className="client-servers" aria-label="Выберите сервер">
      {prompt && <span className="client-server-prompt">Выберите сервер</span>}
      <div className="client-server-grid">
        <ServerRow
          server={servers[0]}
          selected={servers[0].id === selectedServerId}
          favorite={false}
          disabled={disabled}
          index={0}
          onSelect={onSelect}
        />
      </div>
    </section>;
  }

  const renderRows = (items, offset = 0) => items.map((server, index) => (
    <ServerRow
      key={server.id}
      server={server}
      selected={!autoActive && server.id === selectedServerId}
      favorite={favorites.includes(server.id)}
      ping={pings[server.id]}
      disabled={disabled}
      index={offset + index}
      onSelect={select}
      onFavorite={toggleFavorite}
    />
  ));

  return <section className="client-servers is-scalable" aria-label="Выберите сервер">
    {prompt && <span className="client-server-prompt">Выберите сервер</span>}
    <div className="client-server-tools">
      <input
        type="search"
        value={query}
        aria-label="Найти сервер"
        placeholder="Поиск сервера"
        onChange={(event) => setQuery(event.target.value)}
      />
      <div className="client-server-filters" aria-label="Фильтр серверов">
        {[
          ['all', 'Все'],
          ['favorites', '★'],
          ['recent', 'Недавние'],
        ].map(([id, label]) => <button
          type="button"
          className={view === id ? 'is-active' : ''}
          aria-pressed={view === id}
          key={id}
          onClick={() => setView(id)}
        >{label}</button>)}
        <button type="button" disabled={checking || !visible.length} onClick={checkVisible}>
          {checking ? 'Проверяем…' : 'Проверить TCP'}
        </button>
      </div>
    </div>

    <div className="client-server-pinned">
      <button
        className={`client-server-auto${autoActive ? ' is-selected' : ''}`}
        type="button"
        aria-pressed={autoActive}
        disabled={disabled || !servers.length}
        onClick={() => select(autoServer(servers)?.id, true)}
      >
        <strong>Auto</strong>
        <small>Первый стабильный сервер</small>
      </button>
      {selected && !autoActive && <ServerRow
        server={selected}
        selected
        favorite={favorites.includes(selected.id)}
        ping={pings[selected.id]}
        disabled={disabled}
        index={0}
        onSelect={select}
        onFavorite={toggleFavorite}
      />}
    </div>

    <div className={`client-server-scroll${leaving ? ' is-leaving' : ''}`} key={`${serverKey}:${revealVersion}`}>
      {!visible.length && <p className="client-server-empty">Серверы не найдены</p>}
      {grouped ? groupServers(visible).map(([group, items]) => {
        const isCollapsed = collapsed.includes(group);
        return <section className="client-server-group" key={group}>
          <button
            className="client-server-group-toggle"
            type="button"
            aria-expanded={!isCollapsed}
            onClick={() => setCollapsed((current) => current.includes(group)
              ? current.filter((item) => item !== group)
              : [...current, group])}
          >{group} <small>{items.length}</small></button>
          {!isCollapsed && <div className="client-server-grid">{renderRows(items)}</div>}
        </section>;
      }) : <div className="client-server-grid">{renderRows(visible)}</div>}
      {pageCount > 1 && <nav className="client-server-pages" aria-label="Страницы серверов">
        <button className="client-server-more" type="button" disabled={page === 0} onClick={() => setPage((current) => current - 1)}>Назад</button>
        <span>{page + 1} / {pageCount}</span>
        <button className="client-server-more" type="button" disabled={page + 1 === pageCount} onClick={() => setPage((current) => current + 1)}>Дальше</button>
      </nav>}
    </div>
  </section>;
}
