"use client"

import { useEffect, useMemo, useRef, useState, type KeyboardEvent, type ReactNode } from "react"
import type { ServerStatus, ServerType } from "@/lib/data"
import { Flag } from "@/components/flag"
import { StatusDot } from "@/components/status-dot"
import { Badge } from "@/components/reui/badge"
import { IconTile } from "@/components/reui/icon-tile"
import {
  Frame,
  FrameHeader,
  FramePanel,
  FrameTitle,
} from "@/components/reui/frame"
import {
  Item,
  ItemActions,
  ItemContent,
  ItemMedia,
  ItemTitle,
} from "@/components/ui/item"
import { ScrollArea } from "@/components/ui/scroll-area"
import { Spinner } from "@/components/ui/spinner"
import {
  InputGroup,
  InputGroupAddon,
  InputGroupInput,
} from "@/components/ui/input-group"
import { cn } from "@/lib/utils"
import { LayersIcon, SearchIcon, ServerIcon } from "lucide-react"

/** Preview: https://reui.io/preview/base/list-9 · https://reui.io/docs/components/base/icon-tile · https://reui.io/docs/components/base/frame · https://reui.io/docs/components/base/badge */
export const ALL_SERVERS_ID = "all"

export interface ServerTileItem {
  id: string
  name: string
  country?: string
  status?: ServerStatus
  type?: ServerType
  count?: number
  enabled?: boolean
  selectable?: boolean
  title?: string
  site?: string
  host?: string
  meta?: string
}

function typeBadgeVariant(
  type: ServerType,
): "focus-light" | "info-light" | "success-light" {
  if (type === "jump-host") return "focus-light"
  if (type === "home-router") return "success-light"
  return "info-light"
}

function typeBadgeLabel(type: ServerType): string {
  if (type === "jump-host") return "JH"
  if (type === "home-router") return "HR"
  return "EN"
}

function ServerTypeBadge({ type }: { type: ServerType }) {
  return (
    <Badge variant={typeBadgeVariant(type)} size="xs" className="font-mono">
      {typeBadgeLabel(type)}
    </Badge>
  )
}

function hostnameOf(item: ServerTileItem): string {
  return item.name || item.host || ""
}

function matchesQuery(item: ServerTileItem, q: string): boolean {
  if (!q) return true
  const hay = [item.name, item.title ?? "", item.host ?? "", item.site ?? "", item.country ?? ""]
    .join(" ")
    .toLowerCase()
  return hay.includes(q)
}

function isSelectable(item: ServerTileItem): boolean {
  return item.selectable !== false
}

function ServerTileRail({
  items,
  selectedId,
  onSelect,
  allCount = 0,
  showHeader = true,
  showAll = true,
  showCount = true,
  showType = true,
  headerRight,
  loading = false,
  className,
}: {
  items: ServerTileItem[]
  selectedId: string
  onSelect: (id: string) => void
  allCount?: number
  showHeader?: boolean
  showAll?: boolean
  showCount?: boolean
  showType?: boolean
  headerRight?: ReactNode
  loading?: boolean
  className?: string
}) {
  const [query, setQuery] = useState("")
  const q = query.trim().toLowerCase()
  const listRef = useRef<HTMLDivElement>(null)

  const filtered = useMemo(
    () => items.filter((item) => matchesQuery(item, q)),
    [items, q],
  )

  const uniqueSites = useMemo(() => {
    const sites = new Set(
      filtered.map((item) => item.site?.trim()).filter((site): site is string => Boolean(site)),
    )
    return sites.size
  }, [filtered])

  const groupBySite = uniqueSites >= 2 && !q

  const groups = useMemo(() => {
    if (!groupBySite) {
      return [{ site: "", items: filtered }]
    }
    const bySite = new Map<string, ServerTileItem[]>()
    for (const item of filtered) {
      const site = item.site?.trim() || "—"
      const list = bySite.get(site)
      if (list) list.push(item)
      else bySite.set(site, [item])
    }
    return [...bySite.entries()].map(([site, siteItems]) => ({ site, items: siteItems }))
  }, [filtered, groupBySite])

  const showAllTile = showAll && !q

  const resolvedId = useMemo(() => {
    if (showAll && selectedId === ALL_SERVERS_ID) return ALL_SERVERS_ID
    if (items.some((item) => item.id === selectedId)) return selectedId
    if (showAll) return ALL_SERVERS_ID
    return items.find(isSelectable)?.id ?? items[0]?.id ?? ""
  }, [items, selectedId, showAll])

  useEffect(() => {
    if (resolvedId && resolvedId !== selectedId) onSelect(resolvedId)
  }, [onSelect, resolvedId, selectedId])

  const selectableIds = useMemo(() => {
    const ids: string[] = []
    if (showAllTile) ids.push(ALL_SERVERS_ID)
    for (const item of filtered) {
      if (isSelectable(item)) ids.push(item.id)
    }
    return ids
  }, [filtered, showAllTile])

  function moveSelection(delta: number) {
    if (selectableIds.length === 0) return
    const idx = selectableIds.indexOf(resolvedId)
    const nextIdx =
      idx < 0
        ? delta > 0 ? 0 : selectableIds.length - 1
        : Math.min(selectableIds.length - 1, Math.max(0, idx + delta))
    const nextId = selectableIds[nextIdx]
    if (nextId) onSelect(nextId)
  }

  function handleListKeyDown(event: KeyboardEvent<HTMLDivElement>) {
    if (loading) return
    if (event.key === "ArrowDown") {
      event.preventDefault()
      moveSelection(1)
      return
    }
    if (event.key === "ArrowUp") {
      event.preventDefault()
      moveSelection(-1)
      return
    }
    if (event.key === "Home") {
      event.preventDefault()
      if (selectableIds[0]) onSelect(selectableIds[0])
      return
    }
    if (event.key === "End") {
      event.preventDefault()
      const last = selectableIds[selectableIds.length - 1]
      if (last) onSelect(last)
    }
  }

  const allItem: ServerTileItem = {
    id: ALL_SERVERS_ID,
    name: "Все серверы",
    title: "Все серверы",
    count: allCount,
    meta: String(allCount),
  }

  return (
    <Frame dense spacing="sm" className={cn("flex h-full min-h-0 w-full flex-col", className)}>
      <FramePanel className="flex min-h-0 flex-1 flex-col gap-0 p-0">
        <FrameHeader className="flex flex-col gap-2 border-b px-3 py-2">
          {showHeader ? (
            <div className="flex items-center justify-between gap-2">
              <FrameTitle className="text-xs font-medium uppercase tracking-wide text-muted-foreground">
                Серверы
              </FrameTitle>
              <span className="flex items-center gap-1.5">
                {loading ? <Spinner className="size-3.5 text-muted-foreground" /> : null}
                {headerRight}
              </span>
            </div>
          ) : headerRight || loading ? (
            <div className="flex justify-end gap-1.5">
              {loading ? <Spinner className="size-3.5 text-muted-foreground" /> : null}
              {headerRight}
            </div>
          ) : null}
          <InputGroup>
            <InputGroupAddon>
              <SearchIcon className="size-3.5" />
            </InputGroupAddon>
            <InputGroupInput
              value={query}
              onChange={(e) => setQuery(e.target.value)}
              placeholder="Поиск…"
              aria-label="Поиск сервера"
              disabled={loading}
            />
          </InputGroup>
        </FrameHeader>
        <ScrollArea className="min-h-0 flex-1">
          <div
            ref={listRef}
            className="flex flex-col gap-0.5 p-1.5"
            role="listbox"
            aria-label="Серверы"
            aria-activedescendant={resolvedId ? `server-tile-${resolvedId}` : undefined}
            tabIndex={0}
            onKeyDown={handleListKeyDown}
          >
            {showAllTile ? (
              <ServerTileButton
                item={allItem}
                selected={resolvedId === ALL_SERVERS_ID}
                onSelect={() => onSelect(ALL_SERVERS_ID)}
                showCount={showCount}
                showType={false}
                icon={
                  <IconTile variant="elevated" size="sm" aria-hidden="true">
                    <LayersIcon className="text-muted-foreground" />
                  </IconTile>
                }
              />
            ) : null}
            {groups.map((group) => (
              <div key={group.site || "__flat__"} className="flex flex-col gap-0.5">
                {groupBySite && group.site ? (
                  <p className="sticky top-0 z-[1] bg-background/95 px-2 py-1 text-[10px] font-bold uppercase tracking-wide text-muted-foreground backdrop-blur-sm">
                    {group.site}
                  </p>
                ) : null}
                {group.items.map((item) => (
                  <ServerTileButton
                    key={item.id}
                    item={item}
                    selected={resolvedId === item.id}
                    onSelect={() => onSelect(item.id)}
                    showCount={showCount}
                    showType={showType}
                    showSite={!groupBySite}
                    icon={
                      <IconTile variant="elevated" size="sm" aria-hidden="true">
                        {item.country ? (
                          <Flag code={item.country} size={16} />
                        ) : (
                          <ServerIcon className="text-muted-foreground" />
                        )}
                      </IconTile>
                    }
                  />
                ))}
              </div>
            ))}
            {filtered.length === 0 && !showAllTile ? (
              <p className="px-2 py-3 text-center text-xs text-muted-foreground">
                {loading
                  ? "Загрузка серверов…"
                  : items.length === 0
                    ? "Нет доступных серверов"
                    : "Ничего не найдено"}
              </p>
            ) : null}
          </div>
        </ScrollArea>
      </FramePanel>
    </Frame>
  )
}

function ServerTileButton({
  item,
  selected,
  onSelect,
  showCount,
  showType,
  showSite = true,
  icon,
}: {
  item: ServerTileItem
  selected: boolean
  onSelect: () => void
  showCount: boolean
  showType: boolean
  showSite?: boolean
  icon: ReactNode
}) {
  const isAll = item.id === ALL_SERVERS_ID
  const selectable = isSelectable(item)
  const hostname = isAll ? "Все серверы" : hostnameOf(item)
  const meta = item.meta ?? (showCount && item.count != null ? String(item.count) : undefined)
  const showStatus = Boolean(item.status && item.status !== "online")

  return (
    <Item
      id={`server-tile-${item.id}`}
      size="xs"
      variant={selected ? "muted" : "default"}
      render={
        <button
          type="button"
          role="option"
          aria-selected={selected}
          title={item.title ?? hostname}
          disabled={!selectable}
          onClick={onSelect}
        />
      }
      className={cn(
        "h-11 min-h-11 flex-nowrap rounded-md py-0",
        selected && "ring-1 ring-border",
        item.enabled === false && !selected && "opacity-40",
        !selectable && "cursor-not-allowed opacity-40 hover:bg-transparent",
      )}
    >
      <ItemMedia>{icon}</ItemMedia>
      <ItemContent className="min-w-0">
        <ItemTitle className="max-w-full min-w-0 gap-1.5 font-mono text-[11px]">
          {showStatus ? <StatusDot status={item.status!} /> : null}
          <span className="min-w-0 truncate">{hostname}</span>
          {!isAll && showSite && item.site ? (
            <Badge variant="outline" size="xs" className="shrink-0 font-mono uppercase">
              {item.site}
            </Badge>
          ) : null}
          {!isAll && showType && item.type ? <ServerTypeBadge type={item.type} /> : null}
        </ItemTitle>
      </ItemContent>
      {meta ? (
        <ItemActions>
          <Badge
            variant={selected ? "secondary" : "outline"}
            size="xs"
            className="tabular-nums"
          >
            {meta}
          </Badge>
        </ItemActions>
      ) : null}
    </Item>
  )
}

export { ServerTileRail, ServerTypeBadge, hostnameOf }
