import {q, qa, ElemJS} from "/static/js/elemjs/elemjs.js"
import {SubscribeButton} from "/static/js/modules/SubscribeButton.js"

const video = q("#video")
const audio = q("#audio")

const videoFormats = new Map()
const audioFormats = new Map()
for (const f of [].concat(
	data.formatStreams.map(f => (f.isAdaptive = false, f)),
	data.adaptiveFormats.map(f => (f.isAdaptive = true, f))
)) {
	if (f.type.startsWith("video")) {
		videoFormats.set(f.itag, f)
	} else {
		audioFormats.set(f.itag, f)
	}
}

function getBestAudioFormat() {
	let best = null
	let aidub = false
	for (const f of audioFormats.values()) {
		if (f.resolution.includes("default")) {
			aidub = true
		}
	}
	for (const f of audioFormats.values()) {
		if (!aidub || f.resolution.includes("default")) {
			if (best === null || f.bitrate > best.bitrate) {
				best = f
			}
		}
	}
	return best
}

class FormatLoader {
	constructor() {
		this.npv = videoFormats.get(q("#video").getAttribute("data-itag"))
		this.npa = null
	}

	play(itag) {
		this.npv = videoFormats.get(itag)
		if (this.npv.isAdaptive) {
			this.npa = getBestAudioFormat()
		} else {
			this.npa = null
		}
		this.update()
	}

	update() {
		const lastTime = video.currentTime
		video.src = this.npv.url
		video.currentTime = lastTime
		if (this.npa) {
			audio.src = this.npa.url
			audio.pause()
			audio.currentTime = lastTime
		} else {
			audio.pause()
			audio.removeAttribute("src")
		}
	}
}

const formatLoader = new FormatLoader()

class PlayManager {
	constructor(media, isAudio) {
		this.media = media
		this.isAudio = isAudio
	}

	isActive() {
		return !this.isAudio || formatLoader.npa
	}

	play() {
		if (this.isActive()) this.media.play()
	}

	pause() {
		if (this.isActive()) this.media.pause()
	}
}

const playManagers = {
	video: new PlayManager(video, false),
	audio: new PlayManager(audio, true)
}

class QualitySelect extends ElemJS {
	constructor() {
		super(q("#quality-select"))
		this.on("input", this.setFormat.bind(this))
		this.setFormat()
	}

	setFormat() {
		const itag = this.element.value
		formatLoader.play(itag)
		video.focus()
	}
}

const qualitySelect = new QualitySelect()

const ignoreNext = {
	play: 0
}

function playbackIntervention(event) {
	console.log(event.target.tagName.toLowerCase(), event.type)
	if (audio.src) {
		let target = event.target
		let other = (event.target === video ? audio : video)
		let targetPlayManager = playManagers[target.tagName.toLowerCase()]
		let otherPlayManager = playManagers[other.tagName.toLowerCase()]
		if (ignoreNext[event.type] > 0) {
			ignoreNext[event.type]--
			return
		}
		switch (event.type) {
		case "durationchange":
			target.ready = false;
			break;
		case "seeked":
			target.ready = false;
			target.pause();
			other.currentTime = target.currentTime;
			break;
		case "play":
			other.currentTime = target.currentTime;
			otherPlayManager.play();
			break;
		case "pause":
			other.currentTime = target.currentTime;
			other.pause();
		case "playing":
			other.currentTime = target.currentTime;
			break;
		case "ratechange":
			other.playbackRate = target.playbackRate;
			break;
		// case "stalled":
		// case "waiting":
			// target.pause();
			// break;
		}
	} else {
		// @ts-ignore this does exist
		// if (event.type == "canplaythrough" && !video.manualPaused) video.play();
	}
}

for (let eventName of ["pause", "play", "seeked"]) {
	video.addEventListener(eventName, playbackIntervention)
}
for (let eventName of ["canplaythrough", "waiting", "stalled", "ratechange"]) {
	video.addEventListener(eventName, playbackIntervention)
	audio.addEventListener(eventName, playbackIntervention)
}

function relativeSeek(seconds) {
	video.currentTime += seconds
}

function playVideo() {
	audio.currentTime = video.currentTime
	let lastTime = video.currentTime
	ignoreNext.play++
	video.play().then(() => {
		const interval = setInterval(() => {
			console.log("checking video", video.currentTime, lastTime)
			if (video.currentTime !== lastTime) {
				clearInterval(interval)
				playManagers.audio.play()
				return
			}
		}, 15)
	})
}

function togglePlaying() {
	if (video.paused) playVideo()
	else video.pause()
}

function toggleFullScreen() {
	if (document.fullscreen) document.exitFullscreen()
	else video.requestFullscreen()
}

video.addEventListener("click", event => {
	event.preventDefault()
	togglePlaying()
})

video.addEventListener("dblclick", event => {
	event.preventDefault()
	toggleFullScreen()
})

document.addEventListener("keydown", event => {
	if (["INPUT", "SELECT", "BUTTON"].includes(event.target.tagName)) return
	if (event.ctrlKey || event.shiftKey || event.altKey || event.metaKey) return
	let caught = true
	if (event.key === "j" || event.key === "n") {
		relativeSeek(-10)
	} else if (["k", "p", " ", "e"].includes(event.key)) {
		togglePlaying()
	} else if (event.key === "l" || event.key === "o") {
		relativeSeek(10)
	} else if (event.key === "ArrowLeft") {
		relativeSeek(-5)
	} else if (event.key === "ArrowRight") {
		relativeSeek(5)
	} else if (event.key >= "0" && event.key <= "9") {
		video.currentTime = video.duration * (+event.key) / 10
	} else if (event.key === "f") {
		toggleFullScreen()
	} else {
		caught = false
	}
	if (caught) event.preventDefault()
})

new SubscribeButton(q("#subscribe"))

const timestamps = qa("[data-clickable-timestamp]")

class Timestamp extends ElemJS {
	constructor(element) {
		super(element)
		this.on("click", this.onClick.bind(this))
	}

	onClick(event) {
		event.preventDefault()
		video.currentTime = event.target.getAttribute("data-clickable-timestamp")
		window.history.replaceState(null, "", event.target.href)
	}
}

timestamps.forEach(el => {
	new Timestamp(el)
})
