const constants = require("../utils/constants")
const cacheManager = require("./cache-manager")
const cacheReaper = require("../background/cache-reaper")

const lowQualityLimit = 480
let dlQueues = []

const isLowQuality = q => Number(q.split("p")[0]) <= lowQualityLimit

class DlQueue {
	constructor() {
		this.lq = []
		this.hq = []
		this.downloadCount = 0 // Ticks up to 3 then downloads an HQ if available
		this.lastOutput = null

		this.updating = false
	}

	async enqueue(videoID, quality) {
		quality = quality ?? "360p"
		let fname = `${videoID}-${quality}`

		// Same download can't be started multiple times
		const existingData = cacheManager.read("download")[fname]
		if ((!existingData || existingData.status != 2) && !downloader.videoExists(fname)) {
			// Sets to queued
			cacheManager.write("download", fname, { status: 1 })

			// Adds to queue
			if (isLowQuality(quality))
				this.lq.push({videoID, quality})
			else
				this.hq.push({videoID, quality})
			if (!this.updating)
				this.update()
		}

		await downloader.waitForDownload(fname)
		return this.lastOutput
	}

	async startDownload(dl) {
		this.lastOutput = await downloader.saveMp4Android(dl.videoID, dl.quality)
	}

	update() {
		this.updating = true
		// Scan caches just before downloading
		cacheReaper.scanCaches()
		this.downloadCount++
		if (this.lq.length > 0 && (this.downloadCount < 3 || this.hq.length == 0))
			this.startDownload(this.lq.pop()).then(() => {
				this.updating = false
				this.update()
			})
		else if (this.hq.length > 0) {
			this.startDownload(this.hq.pop()).then(() => {
				this.updating = false
				this.update()
			})
		} else
			this.updating = false
		if (this.downloadCount == 3)
			this.downloadCount = 0
	}
}

for (let i = 0; i < constants.server_setup.download_queue_threads; i++)
	dlQueues.push(new DlQueue())

async function enqueue(videoID, quality) {
	// Pick the first empty/near-empty download queue
	const isLQ = quality == undefined || isLowQuality(quality)

	let sortedQueues
	if (isLQ) 
		sortedQueues = dlQueues.sort((a, b) => a.lq.length - b.lq.length)
	else
		sortedQueues = dlQueues.sort((a, b) => (a.hq.length + (2 - a.downloadCount)) - (b.hq.length + (2 - b.downloadCount)))

	return await sortedQueues[0].enqueue(videoID, quality)
}

module.exports = {
	enqueue
}

const downloader = require("./downloader")
