/**
 * Pinia — 文件管理器共享状态（路径/列表/权限/目录缓存）
 */
import { defineStore } from 'pinia'
import { ref } from 'vue'
import type { FileEntry, FilesCapabilityResult } from '@/types/api'
import { DEFAULT_FILES_ROOT } from '@/utils/remotePath'
import { FILES_CACHE_MAX_ENTRIES, FILES_CACHE_TTL_MS } from '@/composables/files/constants'

export interface FilesCacheEntry {
  items: FileEntry[]
  at: number
  etag?: string
}

function cacheKey(serverId: number, path: string): string {
  return `${serverId}:${path}`
}

export const useFilesStore = defineStore('files', () => {
  const selectedServer = ref<number | null>(null)
  const currentPath = ref(DEFAULT_FILES_ROOT)
  const files = ref<FileEntry[]>([])
  const loading = ref(false)
  /** 200ms 防抖后才为 true，避免快请求闪 loading */
  const loadingVisible = ref(false)
  const browseError = ref('')
  const filesCapability = ref<FilesCapabilityResult | null>(null)
  const lastReadDeniedPath = ref<string | null>(null)
  const accessHintDismissed = ref(false)
  const setupSudoLoading = ref(false)
  const setupSudoDone = ref(false)
  const pageReady = ref(false)
  /** 路由 watch 与 onMounted 协调 */
  const routeReady = ref(false)
  /** 阻止 v-select 初始化触发 onServerChange */
  const initing = ref(false)

  const fileCache = new Map<string, FilesCacheEntry>()

  function isCacheFresh(entry: FilesCacheEntry): boolean {
    return Date.now() - entry.at <= FILES_CACHE_TTL_MS
  }

  function getCacheEntry(serverId: number, path: string): FilesCacheEntry | null {
    return fileCache.get(cacheKey(serverId, path)) ?? null
  }

  function getCached(serverId: number, path: string): FileEntry[] | null {
    const entry = getCacheEntry(serverId, path)
    if (!entry || !isCacheFresh(entry)) return null
    return entry.items
  }

  function getCachedEtag(serverId: number, path: string): string | undefined {
    return getCacheEntry(serverId, path)?.etag
  }

  function touchCache(serverId: number, path: string) {
    const entry = getCacheEntry(serverId, path)
    if (entry) {
      entry.at = Date.now()
    }
  }

  function setCached(
    serverId: number,
    path: string,
    items: FileEntry[],
    etag?: string,
  ) {
    const key = cacheKey(serverId, path)
    const prev = fileCache.get(key)
    fileCache.set(key, {
      items,
      at: Date.now(),
      etag: etag ?? prev?.etag,
    })
    if (fileCache.size > FILES_CACHE_MAX_ENTRIES) {
      const oldest = [...fileCache.entries()].sort((a, b) => a[1].at - b[1].at)[0]
      if (oldest) fileCache.delete(oldest[0])
    }
  }

  function invalidateCache(serverId?: number | null, path?: string) {
    if (serverId == null) {
      fileCache.clear()
      return
    }
    if (path == null) {
      const prefix = `${serverId}:`
      for (const key of [...fileCache.keys()]) {
        if (key.startsWith(prefix)) fileCache.delete(key)
      }
      return
    }
    fileCache.delete(cacheKey(serverId, path))
  }

  function resetForServerChange() {
    lastReadDeniedPath.value = null
    accessHintDismissed.value = false
    setupSudoDone.value = false
  }

  return {
    selectedServer,
    currentPath,
    files,
    loading,
    loadingVisible,
    browseError,
    filesCapability,
    lastReadDeniedPath,
    accessHintDismissed,
    setupSudoLoading,
    setupSudoDone,
    pageReady,
    routeReady,
    initing,
    getCacheEntry,
    getCached,
    getCachedEtag,
    touchCache,
    setCached,
    invalidateCache,
    resetForServerChange,
  }
})
