import { ref, computed, type Ref } from 'vue'
import { categoryDisplayLabel } from '@/composables/useServerCategories'
import { useServerSearchHistory } from '@/composables/useServerSearchHistory'
import { fetchPagePerPage } from '@/utils/paginatedFetch'
import type { PushServerItem } from './types'

const PUSH_SEARCH_HISTORY = 5

export function usePushServers(pushStatus: Ref<Record<number, string>>) {
  const servers = ref<PushServerItem[]>([])
  const serversLoading = ref(false)
  const serverSearch = ref('')
  const selectedIds = ref<Set<number>>(new Set())

  const { items: pushSearchHistory, loadHistoryOnly, record: recordPushSearch } =
    useServerSearchHistory('push')

  const serverSearchHistory = computed(() =>
    pushSearchHistory.value.slice(0, PUSH_SEARCH_HISTORY),
  )

  function commitServerSearch() {
    void recordPushSearch(serverSearch.value)
  }

  function onServerSearchUpdate(val: string | null) {
    serverSearch.value = val ?? ''
    if (val == null || val === '') {
      void recordPushSearch('')
      return
    }
    const picked = String(val).trim()
    if (pushSearchHistory.value.includes(picked)) {
      serverSearch.value = picked
      void recordPushSearch(picked)
    }
  }

  async function loadSearchHistory() {
    await loadHistoryOnly()
  }

  let refreshTimer: ReturnType<typeof setInterval> | null = null

  async function loadServers(silent = false) {
    if (!silent) serversLoading.value = true
    try {
      const res = await fetchPagePerPage<PushServerItem>('/servers/', {}, 1, -1)
      servers.value = res.items
    } catch {
      servers.value = []
    } finally {
      if (!silent) serversLoading.value = false
    }
  }

  function startAutoRefresh(_isPushing?: () => boolean) {
    stopAutoRefresh()
    refreshTimer = setInterval(() => {
      void loadServers(true)
    }, 30_000)
  }

  function stopAutoRefresh() {
    if (refreshTimer) {
      clearInterval(refreshTimer)
      refreshTimer = null
    }
  }

  const filteredServers = computed(() => {
    if (!serverSearch.value) return servers.value
    const q = serverSearch.value.toLowerCase()
    return servers.value.filter(
      s =>
        s.name.toLowerCase().includes(q) ||
        (s.domain || '').toLowerCase().includes(q) ||
        (s.target_path || '').toLowerCase().includes(q),
    )
  })

  const selectAll = computed(() => {
    const visible = filteredServers.value
    return visible.length > 0 && visible.every(s => selectedIds.value.has(s.id))
  })

  const serversByCategory = computed(() => {
    const groups: Record<string, PushServerItem[]> = {}
    for (const s of filteredServers.value) {
      const key = s.category?.trim() || 'uncategorized'
      if (!groups[key]) groups[key] = []
      groups[key].push(s)
    }
    return Object.entries(groups)
      .map(([category, list]) => ({
        category,
        label: categoryDisplayLabel(category),
        servers: list,
      }))
      .sort((a, b) => {
        if (a.category === 'uncategorized') return 1
        if (b.category === 'uncategorized') return -1
        return a.label.localeCompare(b.label, 'zh')
      })
  })

  function isCategoryAllSelected(category: string): boolean {
    const group = serversByCategory.value.find(g => g.category === category)
    if (!group || group.servers.length === 0) return false
    return group.servers.every(s => selectedIds.value.has(s.id))
  }

  function toggleCategory(category: string) {
    const group = serversByCategory.value.find(g => g.category === category)
    if (!group) return
    const next = new Set(selectedIds.value)
    const allSelected = group.servers.every(srv => next.has(srv.id))
    for (const srv of group.servers) {
      if (allSelected) next.delete(srv.id)
      else next.add(srv.id)
    }
    selectedIds.value = next
  }

  function toggleServer(id: number) {
    const next = new Set(selectedIds.value)
    if (next.has(id)) next.delete(id)
    else next.add(id)
    selectedIds.value = next
  }

  function toggleAll() {
    const visible = filteredServers.value
    const allSelected = visible.length > 0 && visible.every(s => selectedIds.value.has(s.id))
    const next = new Set(selectedIds.value)
    for (const srv of visible) {
      if (allSelected) next.delete(srv.id)
      else next.add(srv.id)
    }
    selectedIds.value = next
  }

  return {
    servers,
    serversLoading,
    serverSearch,
    serverSearchHistory,
    selectedIds,
    pushStatus,
    filteredServers,
    selectAll,
    serversByCategory,
    loadServers,
    loadSearchHistory,
    commitServerSearch,
    onServerSearchUpdate,
    startAutoRefresh,
    stopAutoRefresh,
    isCategoryAllSelected,
    toggleCategory,
    toggleServer,
    toggleAll,
  }
}
