/**
 * 竖滑视频资源缓存（App 端落盘 + 全端预取调度）
 * - App：downloadFile → saveFile，LRU 淘汰
 * - H5/小程序：依赖 video http-cache + 仅做预连接（不强制落盘）
 */

const INDEX_KEY = 'hl88app:feed_video_cache_index'
const MAX_ENTRIES = 12
const MAX_BYTES = 120 * 1024 * 1024
const MAX_CONCURRENT = 2

/** @type {Map<string, { path: string, size: number, atime: number }>} */
const memory = new Map()
/** @type {Map<string, Promise<string>>} */
const inflight = new Map()
/** @type {string[]} */
const waitQueue = []
let activeCount = 0
let indexLoaded = false

function canPersistFiles() {
	// #ifdef APP-PLUS
	return true
	// #endif
	return false
}

function hashUrl(url) {
	let h = 0
	const s = String(url)
	for (let i = 0; i < s.length; i++) {
		h = (h << 5) - h + s.charCodeAt(i)
		h |= 0
	}
	return `v${Math.abs(h)}`
}

function loadIndex() {
	if (indexLoaded) return
	indexLoaded = true
	try {
		const raw = uni.getStorageSync(INDEX_KEY)
		if (!raw || typeof raw !== 'object') return
		Object.keys(raw).forEach((url) => {
			const row = raw[url]
			if (row && row.path) memory.set(url, row)
		})
	} catch (_) {}
}

function persistIndex() {
	try {
		const payload = {}
		memory.forEach((row, url) => {
			payload[url] = row
		})
		uni.setStorageSync(INDEX_KEY, payload)
	} catch (_) {}
}

function touch(url) {
	const row = memory.get(url)
	if (row) row.atime = Date.now()
}

function totalBytes() {
	let sum = 0
	memory.forEach((row) => {
		sum += Number(row.size) || 0
	})
	return sum
}

function evictLru() {
	while (memory.size >= MAX_ENTRIES || totalBytes() > MAX_BYTES) {
		let oldestUrl = ''
		let oldestAt = Infinity
		memory.forEach((row, url) => {
			if (row.atime < oldestAt) {
				oldestAt = row.atime
				oldestUrl = url
			}
		})
		if (!oldestUrl) break
		const victim = memory.get(oldestUrl)
		memory.delete(oldestUrl)
		if (victim && victim.path) {
			// #ifdef APP-PLUS
			uni.removeSavedFile({ filePath: victim.path, complete: () => {} })
			// #endif
		}
	}
	persistIndex()
}

function pumpQueue() {
	if (activeCount >= MAX_CONCURRENT || !waitQueue.length) return
	const url = waitQueue.shift()
	if (!url || memory.has(url) || inflight.has(url)) {
		pumpQueue()
		return
	}
	activeCount += 1
	const job = downloadAndSave(url)
		.then((local) => {
			if (local) {
				memory.set(url, { path: local, size: 0, atime: Date.now() })
				evictLru()
			}
			return local || url
		})
		.finally(() => {
			activeCount -= 1
			inflight.delete(url)
			pumpQueue()
		})
	inflight.set(url, job)
}

function downloadAndSave(url) {
	return new Promise((resolve) => {
		// #ifdef APP-PLUS
		uni.downloadFile({
			url,
			success: (res) => {
				if (res.statusCode !== 200 || !res.tempFilePath) {
					resolve('')
					return
				}
				uni.saveFile({
					tempFilePath: res.tempFilePath,
					success: (saved) => resolve(saved.savedFilePath || ''),
					fail: () => resolve('')
				})
			},
			fail: () => resolve('')
		})
		// #endif
		// #ifndef APP-PLUS
		resolve('')
		// #endif
	})
}

/**
 * 解析可播放地址：有本地缓存则返回 file:// 路径
 * @param {string} remoteUrl
 */
export async function resolvePlaybackUrl(remoteUrl) {
	if (!remoteUrl) return ''
	loadIndex()
	if (!canPersistFiles()) return remoteUrl

	const cached = memory.get(remoteUrl)
	if (cached && cached.path) {
		touch(remoteUrl)
		return cached.path
	}

	if (inflight.has(remoteUrl)) {
		return inflight.get(remoteUrl)
	}

	const job = downloadAndSave(remoteUrl)
		.then((local) => {
			if (local) {
				uni.getSavedFileInfo({
					filePath: local,
					success: (info) => {
						memory.set(remoteUrl, {
							path: local,
							size: info.size || 0,
							atime: Date.now()
						})
						evictLru()
					},
					fail: () => {
						memory.set(remoteUrl, { path: local, size: 0, atime: Date.now() })
						evictLru()
					}
				})
				return local
			}
			return remoteUrl
		})
		.finally(() => inflight.delete(remoteUrl))

	inflight.set(remoteUrl, job)
	return job
}

/**
 * 后台预取（不阻塞当前播放）
 * @param {string} remoteUrl
 * @param {'high'|'low'} [priority]
 */
export function prefetchPlaybackUrl(remoteUrl, priority = 'low') {
	if (!remoteUrl || !canPersistFiles()) return
	loadIndex()
	if (memory.has(remoteUrl) || inflight.has(remoteUrl)) return
	if (waitQueue.includes(remoteUrl)) return
	if (priority === 'high') waitQueue.unshift(remoteUrl)
	else waitQueue.push(remoteUrl)
	pumpQueue()
}

/** 按当前索引预取相邻视频 */
export function prefetchNeighbors(clips, centerIndex, toRemoteUrl) {
	if (!Array.isArray(clips) || !clips.length) return
	const order = [centerIndex + 1, centerIndex - 1, centerIndex + 2]
	order.forEach((idx, i) => {
		const clip = clips[idx]
		if (!clip) return
		const remote = toRemoteUrl(clip)
		if (!remote) return
		prefetchPlaybackUrl(remote, i === 0 ? 'high' : 'low')
	})
}

export function clearVideoAssetCache() {
	memory.forEach((row) => {
		if (row.path) {
			// #ifdef APP-PLUS
			uni.removeSavedFile({ filePath: row.path, complete: () => {} })
			// #endif
		}
	})
	memory.clear()
	inflight.clear()
	waitQueue.length = 0
	activeCount = 0
	try {
		uni.removeStorageSync(INDEX_KEY)
	} catch (_) {}
}

export function readCachedPlaybackUrl(remoteUrl) {
	loadIndex()
	const row = memory.get(remoteUrl)
	return row && row.path ? row.path : ''
}

/** 本地文件损坏时剔除并回退远程播放 */
export function dropCachedPlaybackUrl(remoteUrl) {
	if (!remoteUrl) return
	const row = memory.get(remoteUrl)
	memory.delete(remoteUrl)
	inflight.delete(remoteUrl)
	const idx = waitQueue.indexOf(remoteUrl)
	if (idx >= 0) waitQueue.splice(idx, 1)
	if (row && row.path) {
		// #ifdef APP-PLUS
		uni.removeSavedFile({ filePath: row.path, complete: () => {} })
		// #endif
	}
	persistIndex()
}
