import { http } from '@/api'
import { joinRemotePath, normalizeRemotePath } from '@/utils/remotePath'
import type { FileEntry } from '@/types/api'

/** 浏览器内编辑 / 预加载上限（300KB） */
export const FILE_PRELOAD_MAX_BYTES = 300 * 1024

const MAX_PRELOAD_FILES_PER_DIR = 40
const PRELOAD_CONCURRENCY = 4

const contentCache = new Map<string, string>()

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

function parentDirOf(remotePath: string): string {
  const p = normalizeRemotePath(remotePath)
  const idx = p.lastIndexOf('/')
  if (idx <= 0) return '/'
  return p.slice(0, idx) || '/'
}

export function clearFilePreloadCache(): void {
  contentCache.clear()
}

/** 仅保留当前目录下文件的缓存，避免跨目录无限增长 */
export function pruneFilePreloadCache(serverId: number, dirPath: string): void {
  const normDir = normalizeRemotePath(dirPath)
  for (const key of [...contentCache.keys()]) {
    if (!key.startsWith(`${serverId}:`)) {
      contentCache.delete(key)
      continue
    }
    const remotePath = key.slice(`${serverId}:`.length)
    if (parentDirOf(remotePath) !== normDir) {
      contentCache.delete(key)
    }
  }
}

export function invalidateCachedFile(serverId: number, remotePath: string): void {
  contentCache.delete(cacheKey(serverId, remotePath))
}

export function isPreloadEligible(item: Pick<FileEntry, 'type' | 'size'>): boolean {
  if (item.type !== 'file') return false
  const size = item.size ?? 0
  return size > 0 && size <= FILE_PRELOAD_MAX_BYTES
}

export function exceedsEditorMaxSize(size: number | undefined): boolean {
  return size != null && size > 0 && size > FILE_PRELOAD_MAX_BYTES
}

function parseReadFileResponse(res: { content?: string } | string): string {
  return typeof res === 'string' ? res : (res.content ?? JSON.stringify(res, null, 2))
}

/** 读取远程文件；命中预加载缓存则不再请求 */
export async function readRemoteFileContent(
  serverId: number,
  remotePath: string,
  maxSize: number = FILE_PRELOAD_MAX_BYTES,
): Promise<string> {
  const key = cacheKey(serverId, remotePath)
  const hit = contentCache.get(key)
  if (hit !== undefined) return hit

  const res = await http.post<{ content?: string } | string>('/sync/read-file', {
    server_id: serverId,
    path: normalizeRemotePath(remotePath),
    max_size: maxSize,
  })
  const content = parseReadFileResponse(res)
  contentCache.set(key, content)
  return content
}

/** 目录加载完成后后台预读 ≤300KB 的普通文件 */
export function preloadDirectoryFiles(
  serverId: number,
  dirPath: string,
  items: FileEntry[],
): void {
  const candidates = items
    .filter(isPreloadEligible)
    .sort((a, b) => (a.size ?? 0) - (b.size ?? 0))
    .slice(0, MAX_PRELOAD_FILES_PER_DIR)

  if (!candidates.length) return

  let next = 0
  const worker = async () => {
    while (next < candidates.length) {
      const item = candidates[next++]
      const remotePath = joinRemotePath(dirPath, item.name)
      const key = cacheKey(serverId, remotePath)
      if (contentCache.has(key)) continue
      try {
        await readRemoteFileContent(serverId, remotePath)
      } catch {
        // 预加载失败不影响浏览
      }
    }
  }

  const workers = Math.min(PRELOAD_CONCURRENCY, candidates.length)
  void Promise.all(Array.from({ length: workers }, () => worker()))
}
