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

/** 浏览器内编辑 / 查看上限（2MB）—— 超过此大小则提示下载 */
export const FILE_EDITOR_MAX_BYTES = 2 * 1024 * 1024

const MAX_PRELOAD_FILES_PER_DIR = 40
const PRELOAD_CONCURRENCY = 4

/** 远程文件读取结果，包含冲突检测所需元数据 */
export interface RemoteFileReadResult {
  content: string
  /** 服务端 mtime（Unix 秒），null 表示获取失败 */
  mtime: number | null
  /** 服务端 sha256hex，null 表示获取失败 */
  etag: string | null
  /** 原始行尾风格，服务端探测 */
  eol: 'LF' | 'CRLF'
}

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

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_EDITOR_MAX_BYTES
}

interface RawReadFileResponse {
  content?: string
  mtime?: number | null
  etag?: string | null
  eol?: 'LF' | 'CRLF'
}

function parseReadFileResponse(res: RawReadFileResponse | string): RemoteFileReadResult {
  if (typeof res === 'string') {
    return { content: res, mtime: null, etag: null, eol: 'LF' }
  }
  const content = res.content ?? JSON.stringify(res, null, 2)
  return {
    content,
    mtime: res.mtime ?? null,
    etag: res.etag ?? null,
    eol: res.eol ?? 'LF',
  }
}

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

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

/** 目录加载完成后后台预读 ≤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()))
}
