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';
const SIMPLE_SERVER_LIMIT = 5;

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 serverHealthText(ping) {
  if (ping?.error) return 'Проверка недоступна';
  if (ping?.ok) return `${ping.latency} мс`;
  return ping ? 'Недоступен' : null;
}

function ServerHealth({ ping, fallback }) {
  const health = fallback || serverHealthText(ping);
  if (!health && !ping?.checking) return null;

  return <small
    className={`client-server-health${ping?.checking ? ' is-checking' : ''}`}
    title={ping?.checkedAt || undefined}
    aria-label={ping?.checking ? 'Проверяем пинг' : health}
  >
    <span aria-hidden="true">{health}</span>
    <span className="client-server-health-checking" aria-hidden="true">Проверяем…</span>
  </small>;
}

function ServerCheckButton({ checking, disabled, onClick }) {
  return <button
    className={`client-server-check${checking ? ' is-checking' : ''}`}
    type="button"
    aria-label={checking ? 'Проверяем пинг серверов' : 'Проверить пинг серверов'}
    disabled={checking || disabled}
    onClick={onClick}
  >
    <span>Проверить пинг</span>
    <svg viewBox="0 0 24 24" aria-hidden="true">
      <path d="M21 12a9 9 0 0 0-15.2-6.5L3 8m0-5v5h5M3 12a9 9 0 0 0 15.2 6.5L21 16m0 5v-5h-5" />
    </svg>
  </button>;
}

function ServerRow({ server, selected, favorite, ping, disabled, index, onSelect, onFavorite }) {
  const health = ping?.checking ? 'Проверяем пинг' : serverHealthText(ping);

  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 ? `, ${health}` : ''}`}
      style={{ '--server-index': Math.min(index, 7) }}
      onClick={() => onSelect(server.id)}
    >
      <strong>{server.label}</strong>
      <ServerHealth ping={ping} />
    </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 [advanced, setAdvanced] = useState(false);
  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;
    const startedAt = performance.now();
    setChecking(true);
    setPings((current) => ({
      ...current,
      ...Object.fromEntries(ids.map((id) => [id, { ...current[id], checking: true }])),
    }));
    try {
      const data = await api.servers.ping(ids);
      setPings((current) => ({
        ...current,
        ...Object.fromEntries((data.results || []).map((result) => [result.id, { ...result, checking: true }])),
      }));
    } catch {
      setPings((current) => ({
        ...current,
        ...Object.fromEntries(ids.map((id) => [id, { error: true, checking: true, checkedAt: new Date().toISOString() }])),
      }));
    } finally {
      await new Promise((resolve) => setTimeout(resolve, Math.max(0, 700 - (performance.now() - startedAt))));
      setPings((current) => ({
        ...current,
        ...Object.fromEntries(ids.map((id) => [id, { ...current[id], checking: false }])),
      }));
      setChecking(false);
    }
  }

  if (servers.length === 1) {
    return <section className="client-servers" aria-label="Выберите сервер">
      {prompt && <span className="client-server-prompt">Выберите сервер</span>}
      <div className="client-server-toolbar is-single">
        <ServerCheckButton checking={checking} onClick={checkVisible} />
      </div>
      <div className="client-server-grid">
        <ServerRow
          server={servers[0]}
          selected={servers[0].id === selectedServerId}
          favorite={false}
          ping={pings[servers[0].id]}
          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}
    />
  ));

  const simpleServers = [
    ...(selected ? [selected] : []),
    ...servers.filter(({ id }) => id !== selectedServerId),
  ].slice(0, SIMPLE_SERVER_LIMIT);

  return <section className="client-servers is-scalable" aria-label="Выберите сервер">
    {prompt && <span className="client-server-prompt">Выберите сервер</span>}
    <div className="client-server-toolbar">
      <button
        className={`client-server-mode-toggle${advanced ? ' is-open' : ''}`}
        type="button"
        aria-expanded={advanced}
        aria-label={advanced ? 'Скрыть поиск и фильтры' : 'Показать поиск и фильтры'}
        onClick={() => setAdvanced((current) => !current)}
      >
        <span>Поиск и фильтры</span>
        <svg viewBox="0 0 12 8" aria-hidden="true"><path d="m1 1 5 5 5-5" /></svg>
      </button>
      <ServerCheckButton checking={checking} disabled={!servers.length} onClick={checkVisible} />
    </div>

    <div className="client-server-mode-panels">
      <div
        className={`client-server-mode-panel is-simple${advanced ? '' : ' is-open'}`}
        aria-hidden={advanced}
        inert={advanced ? true : undefined}
      >
        <div className="client-server-mode-panel-inner">
          <div className={`client-server-scroll${leaving ? ' is-leaving' : ''}`} key={`simple:${serverKey}:${revealVersion}`}>
            <div className="client-server-grid">
              {simpleServers.map((server, index) => <ServerRow
                key={server.id}
                server={server}
                selected={server.id === selectedServerId}
                ping={pings[server.id]}
                disabled={disabled}
                index={index}
                onSelect={select}
              />)}
            </div>
            {servers.length > simpleServers.length && <p className="client-server-overflow-note">
              Ещё {servers.length - simpleServers.length} — доступны через поиск
            </p>}
          </div>
        </div>
      </div>

      <div
        className={`client-server-mode-panel is-advanced${advanced ? ' is-open' : ''}`}
        aria-hidden={!advanced}
        inert={!advanced ? true : undefined}
      >
        <div className="client-server-mode-panel-inner">
          <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>)}
            </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>
              <ServerHealth
                ping={autoActive ? pings[selectedServerId] : undefined}
                fallback={autoActive ? undefined : 'Первый стабильный сервер'}
              />
            </button>
            {selected && <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={`advanced:${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>
        </div>
      </div>
    </div>
  </section>;
}
