// SPDX-FileCopyrightText: 2025 Weibo, Inc.
//
// SPDX-License-Identifier: Apache-2.0

/**
 * useKnowledgeSidebar - Hook for managing knowledge sidebar state.
 *
 * Combines favorites, recent access, and groups data for the sidebar.
 * Uses the optimized all-grouped API to solve N+1 query problem.
 */

import { useState, useEffect, useCallback, useMemo, useRef } from 'react'
import { knowledgeBaseApi } from '@/apis/knowledge-base'
import { dingtalkDocApi } from '@/apis/dingtalk-doc'
import { getKnowledgeBase } from '@/apis/knowledge'
import { useUser } from '@/features/common/UserContext'
import type {
  KnowledgeBase,
  AllGroupedKnowledgeResponse,
  KnowledgeBaseWithGroupInfo,
  KbGroupInfo,
} from '@/types/knowledge'
import type { KbDataItem } from '../components/KnowledgeGroupListPage'
import type { Group } from '@/types/group'
import type { User } from '@/types/api'

// Storage keys
const RECENT_STORAGE_KEY = 'knowledge-recent-access'
const MAX_RECENT_ITEMS = 5

export type GroupType = 'personal' | 'group' | 'organization' | 'dingtalk'

/** View mode for the knowledge page */
export type ViewMode = 'all' | 'group' | 'kb' | 'groups' | 'dingtalk'

export interface KnowledgeGroup {
  id: string
  type: GroupType
  name: string
  displayName: string
  kbCount: number
  group?: Group
}

export interface RecentAccessItem {
  kbId: number
  kbName: string
  kbType: 'notebook' | 'classic'
  namespace: string
  accessedAt: number
}

// Re-export KbGroupInfo from types for convenience
export type { KbGroupInfo } from '@/types/knowledge'

export interface UseKnowledgeSidebarReturn {
  // Favorites
  favorites: KnowledgeBase[]
  isFavoritesLoading: boolean
  addFavorite: (kbId: number) => Promise<void>
  removeFavorite: (kbId: number) => Promise<void>
  reorderFavorites: (kbIds: number[]) => Promise<void>

  // Recent access
  recentItems: KnowledgeBase[]
  addRecentAccess: (kb: KnowledgeBase) => void
  clearRecentAccess: () => void

  // Groups
  groups: KnowledgeGroup[]
  isGroupsLoading: boolean

  // Selection
  selectedKbId: number | null
  selectedGroupId: string | null
  selectedKb: KnowledgeBase | null
  selectKb: (kb: KnowledgeBase) => void
  syncConvertedKnowledgeBase: (kb: KnowledgeBase) => void
  selectGroup: (groupId: string) => void
  selectGroups: () => void
  clearSelection: () => void

  // View mode
  viewMode: ViewMode
  selectAll: () => void
  selectDingtalk: () => void
  filterGroupId: string | null
  setFilterGroupId: (groupId: string | null) => void

  // All KBs for search and display
  allKnowledgeBases: KnowledgeBase[]
  allKnowledgeBasesWithGroupInfo: KnowledgeBaseWithGroupInfo[]

  // Personal KBs grouped by ownership (for "Personal" group display)
  personalCreatedByMe: KnowledgeBaseWithGroupInfo[]
  personalSharedWithMe: KnowledgeBaseWithGroupInfo[]

  // Get group info for a KB (accepts both KnowledgeBase and KnowledgeBaseWithGroupInfo)
  getKbGroupInfo: (kb: KbDataItem) => KbGroupInfo

  // Current user
  currentUser: User | null

  // DingTalk docs
  dingtalkDocCount: number
  wikispaceDocCount: number
  isDingtalkConfigured: boolean
  isDingtalkLoading: boolean
  isWikispaceConfigured: boolean

  // Summary counts from backend
  summary?: {
    total_count: number
    personal_count: number
    group_count: number
    organization_count: number
  }

  // Refresh
  refreshAll: () => Promise<void>
}

/**
 * Load recent access from localStorage
 */
function loadRecentAccess(): RecentAccessItem[] {
  try {
    const saved = localStorage.getItem(RECENT_STORAGE_KEY)
    return saved ? JSON.parse(saved) : []
  } catch {
    return []
  }
}

/**
 * Save recent access to localStorage
 */
function saveRecentAccess(items: RecentAccessItem[]) {
  try {
    localStorage.setItem(RECENT_STORAGE_KEY, JSON.stringify(items))
  } catch {
    // Ignore storage errors
  }
}

/**
 * Convert KnowledgeBaseWithGroupInfo to KnowledgeBase
 */
function toKnowledgeBase(kb: KnowledgeBaseWithGroupInfo): KnowledgeBase {
  return {
    id: kb.id,
    name: kb.name,
    description: kb.description,
    user_id: kb.user_id,
    namespace: kb.namespace,
    document_count: kb.document_count,
    is_active: true,
    summary_enabled: false,
    kb_type: kb.kb_type || 'notebook',
    max_calls_per_conversation: 10,
    exempt_calls_before_check: 5,
    created_at: kb.created_at,
    updated_at: kb.updated_at,
  }
}

function mergeKnowledgeBase(
  existing: KnowledgeBaseWithGroupInfo,
  updated: KnowledgeBase
): KnowledgeBaseWithGroupInfo {
  return {
    ...existing,
    name: updated.name,
    description: updated.description,
    namespace: updated.namespace,
    document_count: updated.document_count,
    kb_type: updated.kb_type || existing.kb_type,
    user_id: updated.user_id,
    updated_at: updated.updated_at,
    created_at: updated.created_at,
  }
}

export function useKnowledgeSidebar(): UseKnowledgeSidebarReturn {
  const { user } = useUser()

  // Data state - using the new all-grouped API response
  const [allGroupedData, setAllGroupedData] = useState<AllGroupedKnowledgeResponse | null>(null)

  // Loading state
  const [isLoading, setIsLoading] = useState(true)
  const [isFavoritesLoading, setIsFavoritesLoading] = useState(false)

  // Favorites state (will be loaded from API when backend is ready)
  const [favorites, setFavorites] = useState<KnowledgeBase[]>([])

  // Recent access state
  const [recentAccessItems, setRecentAccessItems] = useState<RecentAccessItem[]>(loadRecentAccess)

  // Selection state
  const [selectedKbId, setSelectedKbId] = useState<number | null>(null)
  const [selectedGroupId, setSelectedGroupId] = useState<string | null>(null)
  const [selectedKb, setSelectedKb] = useState<KnowledgeBase | null>(null)

  // View mode state
  const [viewMode, setViewMode] = useState<ViewMode>('all')
  const [filterGroupId, setFilterGroupId] = useState<string | null>(null)

  // DingTalk docs state
  const [dingtalkDocCount, setDingtalkDocCount] = useState(0)
  const [wikispaceDocCount, setWikispaceDocCount] = useState(0)
  const [isDingtalkConfigured, setIsDingtalkConfigured] = useState(false)
  const [isDingtalkLoading, setIsDingtalkLoading] = useState(true)
  const [isWikispaceConfigured, setIsWikispaceConfigured] = useState(false)

  // Load initial data using the optimized all-grouped API
  const loadInitialData = useCallback(async () => {
    setIsLoading(true)
    try {
      const response = await knowledgeBaseApi.getAllGrouped()
      setAllGroupedData(response)
    } catch (error) {
      console.error('Failed to load knowledge sidebar data:', error)
    } finally {
      setIsLoading(false)
    }
  }, [])

  useEffect(() => {
    if (user) {
      loadInitialData()
    }
  }, [user, loadInitialData])

  const loadDingtalkStatus = useCallback(async () => {
    setIsDingtalkLoading(true)
    const [docsResult, wsResult] = await Promise.allSettled([
      dingtalkDocApi.getSyncStatus(),
      dingtalkDocApi.getWikispaceSyncStatus(),
    ])
    if (docsResult.status === 'fulfilled') {
      setDingtalkDocCount(docsResult.value.total_nodes)
      setIsDingtalkConfigured(docsResult.value.is_configured)
    } else {
      setIsDingtalkConfigured(false)
      setDingtalkDocCount(0)
    }
    if (wsResult.status === 'fulfilled') {
      setIsWikispaceConfigured(wsResult.value.is_configured)
      setWikispaceDocCount(wsResult.value.total_nodes)
    } else {
      setIsWikispaceConfigured(false)
      setWikispaceDocCount(0)
    }
    setIsDingtalkLoading(false)
  }, [])

  useEffect(() => {
    if (user) {
      loadDingtalkStatus()
    }
  }, [user, loadDingtalkStatus])

  // Build all knowledge bases with group info list
  const allKnowledgeBasesWithGroupInfo = useMemo((): KnowledgeBaseWithGroupInfo[] => {
    if (!allGroupedData) return []

    const all: KnowledgeBaseWithGroupInfo[] = [
      ...allGroupedData.personal.created_by_me,
      ...allGroupedData.personal.shared_with_me,
      ...allGroupedData.groups.flatMap(g => g.knowledge_bases),
      ...allGroupedData.organization.knowledge_bases,
    ]

    // Remove duplicates by (id, group_id) so the same KB can appear in different groups
    const seen = new Set<string>()
    const deduped = all.filter(kb => {
      const key = `${kb.id}-${kb.group_id}`
      if (seen.has(key)) return false
      seen.add(key)
      return true
    })

    // Sort by updated_at DESC globally (most recent first)
    return deduped.sort((a, b) => {
      const aTime = a.updated_at ? new Date(a.updated_at).getTime() : 0
      const bTime = b.updated_at ? new Date(b.updated_at).getTime() : 0
      return bTime - aTime
    })
  }, [allGroupedData])

  // Build all knowledge bases list for search (without group info)
  const allKnowledgeBases = useMemo((): KnowledgeBase[] => {
    // Dedupe by id for search/recent items
    const seen = new Set<number>()
    return allKnowledgeBasesWithGroupInfo
      .filter(kb => {
        if (seen.has(kb.id)) return false
        seen.add(kb.id)
        return true
      })
      .map(toKnowledgeBase)
  }, [allKnowledgeBasesWithGroupInfo])

  // Build a map from KB ID to group info for quick lookup
  const kbGroupInfoMap = useMemo((): Map<number, KbGroupInfo> => {
    const map = new Map<number, KbGroupInfo>()
    allKnowledgeBasesWithGroupInfo.forEach(kb => {
      map.set(kb.id, {
        groupId: kb.group_id,
        groupName: kb.group_name,
        groupType: kb.group_type,
      })
    })
    return map
  }, [allKnowledgeBasesWithGroupInfo])

  // Get group info for a KB (accepts both KnowledgeBase and KnowledgeBaseWithGroupInfo)
  const getKbGroupInfo = useCallback(
    (kb: KbDataItem): KbGroupInfo => {
      // If kb has source_group (entity-authorized shared KB), show the source group
      if ('source_group' in kb && kb.source_group) {
        return {
          groupId: 'shared',
          groupName: kb.source_group,
          groupType: 'personal-shared',
        }
      }

      // If kb already has group info (KnowledgeBaseWithGroupInfo), use it directly
      if ('group_id' in kb && 'group_name' in kb && 'group_type' in kb) {
        return {
          groupId: kb.group_id,
          groupName: kb.group_name,
          groupType: kb.group_type,
        }
      }

      // Otherwise, look up from the map
      const info = kbGroupInfoMap.get(kb.id)
      if (info) return info

      // Fallback: determine group info from namespace
      if (kb.namespace === 'default') {
        return {
          groupId: 'default',
          groupName: '个人',
          groupType: 'personal',
        }
      }
      return {
        groupId: kb.namespace,
        groupName: kb.namespace,
        groupType: 'group',
      }
    },
    [kbGroupInfoMap]
  )

  // Build groups list with KB counts
  const groups = useMemo((): KnowledgeGroup[] => {
    if (!allGroupedData) return []

    const result: KnowledgeGroup[] = []

    // Personal group
    const personalKbCount =
      allGroupedData.summary?.personal_count ??
      allGroupedData.personal.created_by_me.length + allGroupedData.personal.shared_with_me.length
    result.push({
      id: 'personal',
      type: 'personal',
      name: 'personal',
      displayName: '个人',
      kbCount: personalKbCount,
    })

    // Team groups
    allGroupedData.groups.forEach(group => {
      result.push({
        id: `group-${group.group_name}`,
        type: 'group',
        name: group.group_name,
        displayName: group.group_display_name || group.group_name,
        kbCount: group.kb_count,
      })
    })

    // Organization group
    result.push({
      id: 'organization',
      type: 'organization',
      name: allGroupedData.organization.namespace || 'organization',
      displayName: allGroupedData.organization.display_name || '公司',
      kbCount: allGroupedData.summary?.organization_count ?? allGroupedData.organization.kb_count,
    })

    return result
  }, [allGroupedData])

  // Convert recent access items to KnowledgeBase objects
  const recentItems = useMemo(() => {
    return recentAccessItems
      .map(item => allKnowledgeBases.find(kb => kb.id === item.kbId))
      .filter((kb): kb is KnowledgeBase => kb !== undefined)
      .slice(0, MAX_RECENT_ITEMS)
  }, [recentAccessItems, allKnowledgeBases])

  // Favorites management (placeholder - will use API when backend is ready)
  const addFavorite = useCallback(
    async (kbId: number) => {
      setIsFavoritesLoading(true)
      try {
        // TODO: Call API when backend is ready
        // await knowledgeBaseApi.addFavorite(kbId)
        const kb = allKnowledgeBases.find(k => k.id === kbId)
        if (kb) {
          setFavorites(prev => [...prev, kb])
        }
      } finally {
        setIsFavoritesLoading(false)
      }
    },
    [allKnowledgeBases]
  )

  const removeFavorite = useCallback(async (kbId: number) => {
    setIsFavoritesLoading(true)
    try {
      // TODO: Call API when backend is ready
      // await knowledgeBaseApi.removeFavorite(kbId)
      setFavorites(prev => prev.filter(kb => kb.id !== kbId))
    } finally {
      setIsFavoritesLoading(false)
    }
  }, [])

  const reorderFavorites = useCallback(async (kbIds: number[]) => {
    setIsFavoritesLoading(true)
    try {
      // TODO: Call API when backend is ready
      // await knowledgeBaseApi.reorderFavorites(kbIds)
      setFavorites(prev => {
        const kbMap = new Map(prev.map(kb => [kb.id, kb]))
        return kbIds.map(id => kbMap.get(id)).filter((kb): kb is KnowledgeBase => kb !== undefined)
      })
    } finally {
      setIsFavoritesLoading(false)
    }
  }, [])

  // Recent access management
  const addRecentAccess = useCallback((kb: KnowledgeBase) => {
    setRecentAccessItems(prev => {
      const filtered = prev.filter(item => item.kbId !== kb.id)
      const newItem: RecentAccessItem = {
        kbId: kb.id,
        kbName: kb.name,
        kbType: (kb.kb_type as 'notebook' | 'classic') || 'notebook',
        namespace: kb.namespace,
        accessedAt: Date.now(),
      }
      const updated = [newItem, ...filtered].slice(0, MAX_RECENT_ITEMS)
      saveRecentAccess(updated)
      return updated
    })
  }, [])

  const clearRecentAccess = useCallback(() => {
    setRecentAccessItems([])
    saveRecentAccess([])
  }, [])

  // Ref to track the latest intended KB selection, used to discard stale async responses
  const latestSelectedKbIdRef = useRef<number | null>(null)

  // Selection management
  const selectKb = useCallback(
    (kb: KnowledgeBase) => {
      // Record the intended selection before starting any async work
      latestSelectedKbIdRef.current = kb.id
      setSelectedKbId(kb.id)
      setSelectedGroupId(null)
      setViewMode('kb')
      addRecentAccess(kb)

      // For notebook type, set selectedKb immediately with available data to avoid
      // flashing the empty state, then fetch full KB data to get guided_questions
      if (kb.kb_type === 'notebook') {
        setSelectedKb(kb)
        getKnowledgeBase(kb.id)
          .then(fullKb => {
            // Discard stale response if user has since selected a different KB
            setSelectedKb(prev => {
              if (latestSelectedKbIdRef.current !== kb.id) return prev
              return fullKb
            })
          })
          .catch(error => {
            console.error('Failed to fetch full knowledge base data:', error)
          })
      } else {
        setSelectedKb(kb)
      }
    },
    [addRecentAccess]
  )

  const syncConvertedKnowledgeBase = useCallback((updatedKb: KnowledgeBase) => {
    setAllGroupedData(prev => {
      if (!prev) return prev

      const updateList = (items: KnowledgeBaseWithGroupInfo[]) =>
        items.map(item => (item.id === updatedKb.id ? mergeKnowledgeBase(item, updatedKb) : item))

      return {
        ...prev,
        personal: {
          created_by_me: updateList(prev.personal.created_by_me),
          shared_with_me: updateList(prev.personal.shared_with_me),
        },
        groups: prev.groups.map(group => ({
          ...group,
          knowledge_bases: updateList(group.knowledge_bases),
        })),
        organization: {
          ...prev.organization,
          knowledge_bases: updateList(prev.organization.knowledge_bases),
        },
      }
    })

    setSelectedKb(prev => {
      if (!prev || prev.id !== updatedKb.id) return prev
      return {
        ...prev,
        ...updatedKb,
      }
    })

    setFavorites(prev => prev.map(kb => (kb.id === updatedKb.id ? { ...kb, ...updatedKb } : kb)))

    setRecentAccessItems(prev => {
      const next = prev.map(item =>
        item.kbId === updatedKb.id
          ? {
              ...item,
              kbName: updatedKb.name,
              kbType: updatedKb.kb_type || 'notebook',
              namespace: updatedKb.namespace,
            }
          : item
      )
      saveRecentAccess(next)
      return next
    })
  }, [])

  const selectGroup = useCallback((groupId: string) => {
    setSelectedGroupId(groupId)
    setSelectedKbId(null)
    setSelectedKb(null)
    setViewMode('group')
    setFilterGroupId(groupId)
  }, [])

  const selectAll = useCallback(() => {
    setSelectedGroupId(null)
    setSelectedKbId(null)
    setSelectedKb(null)
    setViewMode('all')
    setFilterGroupId(null)
  }, [])

  const selectGroups = useCallback(() => {
    setSelectedGroupId(null)
    setSelectedKbId(null)
    setSelectedKb(null)
    setViewMode('groups')
    setFilterGroupId(null)
  }, [])

  const selectDingtalk = useCallback(() => {
    setSelectedGroupId(null)
    setSelectedKbId(null)
    setSelectedKb(null)
    setViewMode('dingtalk')
    setFilterGroupId(null)
  }, [])

  const clearSelection = useCallback(() => {
    setSelectedKbId(null)
    setSelectedKb(null)
    setSelectedGroupId(null)
    setViewMode('all')
    setFilterGroupId(null)
  }, [])

  // Refresh all data
  const refreshAll = useCallback(async () => {
    await Promise.all([loadInitialData(), loadDingtalkStatus()])
  }, [loadInitialData, loadDingtalkStatus])

  // Personal KBs grouped by ownership
  const personalCreatedByMe = useMemo((): KnowledgeBaseWithGroupInfo[] => {
    return allGroupedData?.personal.created_by_me || []
  }, [allGroupedData])

  const personalSharedWithMe = useMemo((): KnowledgeBaseWithGroupInfo[] => {
    return allGroupedData?.personal.shared_with_me || []
  }, [allGroupedData])

  return {
    // Favorites
    favorites,
    isFavoritesLoading,
    addFavorite,
    removeFavorite,
    reorderFavorites,

    // Recent access
    recentItems,
    addRecentAccess,
    clearRecentAccess,

    // Groups
    groups,
    isGroupsLoading: isLoading,

    // Selection
    selectedKbId,
    selectedGroupId,
    selectedKb,
    selectKb,
    syncConvertedKnowledgeBase,
    selectGroup,
    selectGroups,
    clearSelection,

    // View mode
    viewMode,
    selectAll,
    selectDingtalk,
    filterGroupId,
    setFilterGroupId,

    // All KBs for search and display
    allKnowledgeBases,
    allKnowledgeBasesWithGroupInfo,

    // Personal KBs grouped by ownership
    personalCreatedByMe,
    personalSharedWithMe,

    // Get group info for a KB
    getKbGroupInfo,

    // Current user
    currentUser: user,

    // DingTalk docs
    dingtalkDocCount,
    wikispaceDocCount,
    isDingtalkConfigured,
    isDingtalkLoading,
    isWikispaceConfigured,

    // Summary from backend
    summary: allGroupedData?.summary,

    // Refresh
    refreshAll,
  }
}

export default useKnowledgeSidebar
