var cache = cache || {}
var layer = 'descriptions'
var baseURL = 'https://pad.ma'
var imageResolution = 480
var videoExtension

async function pandoraAPI(action, data) {
    var url = baseURL + '/api/'
    //var url = '/pandoraAPI/'
    var key = JSON.stringify([action, data])
    if (!cache[key]) {
        var response = await fetch(url, {
            method: 'POST',
            headers: {'Content-Type': 'application/json'},
            body: JSON.stringify({
                action: action,
                data: data
            })
        })
        cache[key] = await response.json()
    }
    return cache[key]
}

function setVideoSrc(video, src) {
    var ext
    if (!videoExtension) {
        [
            ['video/mp4; codecs="avc1.42E01E, mp4a.40.2"', '.mp4'],
            ['video/webm; codecs="vp8, vorbis"', '.webm'],
        ].forEach(opt => {
            if (videoExtension) { return }
            if (video.canPlayType(opt[0]).replace('no', '')) {
                videoExtension = opt[1]
            }
        })
    }
    video.src = src.replace('.webm', videoExtension)
}

function updatePlayer(video, frame, currentTime, out, src) {
    var rect = frame.getBoundingClientRect();
    video.style.opacity = 0
    video.style.top =  (rect.top + window.scrollY) + 'px'
    video.style.display = 'block';
    if (src) {
        setVideoSrc(video, src)
    }
    //video.poster = frame.querySelector('img').src
    var muted = video.muted
    video.muted = true
    video.currentTime = currentTime
    video.dataset.in = currentTime
    video.dataset.out = out
    video._frame = frame
    const show = event => {
        video.style.opacity = 1
        video.muted = muted
        video.removeEventListener('seeked', show)
    }
    video.addEventListener('seeked', show)
    video.play()
}

function isElementInViewport (el) {
    var rect = el.getBoundingClientRect();
    return (
        rect.top >= 0 &&
        rect.left >= 0 &&
        rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && /* or $(window).height() */
        rect.right <= (window.innerWidth || document.documentElement.clientWidth) /* or $(window).width() */
    );
}

function onVisibilityChange(el, callback) {
    var old_visible;
    return function () {
        var visible = isElementInViewport(el);
        if (visible != old_visible) {
            old_visible = visible;
            if (visible) {
                el.classList.add('visible')
            } else {
                el.classList.remove('visible')
            }
            if (typeof callback == 'function') {
                callback(visible);
            }
        }
    }
}

function scrollTo(element) {
    var delta = element.offsetTop - document.scrollingElement.scrollTop,
        duration = 1000, t = 40, n = duration / t,
        step = delta / n;

    function scroll() {
        if (document.scrollingElement.scrollTop + step > element.offsetTop) {
            document.scrollingElement.scrollTop = element.offsetTop
            n = 0
        } else {
            document.scrollingElement.scrollTop += step
        }
        n--
        if (n) setTimeout(scroll, t)
    }
    scroll()
}

function timeupdate(event) {
    if (event.target.dataset.out && event.target.dataset.in) {
        var in_= parseFloat(event.target.dataset.in)
        var out_= parseFloat(event.target.dataset.out)
        if (event.target.currentTime >= out_) {
            /*
            var next
            if (event.target._frame) {
                next = event.target._frame.parentElement.nextSibling
                if (next) {
                    next = next.querySelector('.frame')
                }
            }
            if (next) {
                scrollTo(next)
            } else {
                event.target.pause()
            }
            */
            if (config.pause) {
                event.target.pause()
            } else {
                event.target.currentTime = in_
            }
        }
    }
}

function formatInfo(config, ascroll) {
    var info = document.createElement('div')
    var h1 = document.createElement('h1')
    h1.innerHTML = config.title
    info.appendChild(h1)
    var h2 = document.createElement('h2')
    h2.innerHTML = config.byline
    info.appendChild(h2)
    var div = document.createElement('div')
    div.classList.add('intro')
    div.innerHTML = config.body
    info.appendChild(div)
    ascroll.appendChild(info)
    return info
}

function showOverlay(event) {
    event.stopPropagation()
    event.preventDefault()
    document.querySelectorAll('#video-overlay').forEach(element => element.remove())
    var video = event.target
    var rect = video.getBoundingClientRect();
    var overlay = document.createElement('div')
    overlay.id = 'video-overlay'
    overlay.style.top = video.style.top
    overlay.style.width = rect.width + 'px'
    overlay.style.height = rect.height + 'px'
    overlay.style.position = 'absolute'
    overlay.style.display = 'flex'
    overlay.style.alignItems = 'center'
    overlay.style.justifyContent = 'center'
    overlay.style.fontSize = '45px'
    video.controls = false

    var off = `🔇`
    var on = `🔊`

    if (video.muted) {
            overlay.innerHTML = off
    } else {
            overlay.innerHTML = on
    }
    overlay.addEventListener('click', event=> {
        video.muted = !video.muted
        if (video.muted) {
            overlay.innerHTML = off
        } else {
            overlay.innerHTML = on
        }
    })
    var timeout = setTimeout(() => {
        video.controls = false
        overlay.remove()
    }, 3000)
    overlay.addEventListener('mousemove', event=> {
        clearTimeout(timeout)
        timeout = setTimeout(() => {
            video.controls = false
            overlay.remove()
        }, 500)
    })
    video.parentElement.appendChild(overlay)

}

function renderAnnotation(config, video, ascroll, annotation) {
    var div = document.createElement('div')
    div.classList.add('annotation')

    var color1 = `hsl(${annotation.color1.hue}, 70%, 75%)`
    var color2 = `hsl(${annotation.color2.hue}, 70%, 75%)`
    if (!config.first) {
        config.first = annotation
        config.info.style.background = color1
    }
    div.style.background = `linear-gradient(to bottom, ${color1}, ${color2})`;
    var figcaption = ''
    if (annotation.title) {
        figcaption = `<figcaption><a href="${baseURL}/${annotation.id}" target="_blank">${annotation.title}</a></figcaption>`
    }
    div.innerHTML = `
        <div class="frame">
            <figure>
                <img src="${baseURL}/${annotation.id.split('/')[0]}/${imageResolution}p${annotation.in}.jpg">
                ${figcaption}
            </figure>
        </div>
        <div class="text">${annotation.value}</div>
    `
    ascroll.appendChild(div)
    var frame = div.querySelector('.frame')
    document.addEventListener('scroll', onVisibilityChange(div.querySelector('.frame'), function(visible) {
        var src
        if (config.edit) {
            src = `${baseURL}/${annotation.id.split('/')[0]}/480p.webm`
        }
        if (config.loaded && visible) {
            updatePlayer(video, frame, annotation['in'], annotation['out'], src)
        }

    }))
}

function renderAnnotations(config) {
    var ascroll = document.querySelector('#ascroll')
    config.loaded = false
    var video = document.createElement('video')
    video.classList.add('player')
    video.playsinline = true
    video.muted = true
    if (config.item) {
        setVideoSrc(video, `${baseURL}/${config.item}/480p.webm`)
    }
    video.addEventListener('timeupdate', timeupdate)
    video.addEventListener('touchstart', showOverlay)
    video.addEventListener('mouseover', showOverlay)
    var box = document.createElement('div')
    box.classList.add('vbox')
    box.appendChild(video)
    ascroll.appendChild(box)

    config.info = formatInfo(config, ascroll)
    config.annotations.forEach(annotation => {
        renderAnnotation(config, video, ascroll, annotation)
    })
    config.loaded = true
    if (config.first) {
        let frame = ascroll.querySelector('.annotation .frame')
        if (frame) {
            var src
            if (config.edit) {
                src = `${baseURL}/${config.first.id.split('/')[0]}/480p.webm`
            }
            updatePlayer(video, frame, config.first['in'], config.first['out'], src)
        }
    }
}

async function loadClips(annotations) {
    var items = annotations.map(annotation => annotation.id.split('/')[0])
    items = [...new Set(items)]
    return pandoraAPI('findClips', {itemsQuery: {
        conditions: [{key: 'id', operator: '&', value: items}]
    }, range: [0, 10000], keys: [
        'id', 'hue', 'saturation', 'lightness'
    ]}).then(response => {
        var colors = {}
        response.data.items.forEach(clip => {
            colors[clip.id] = clip
        })
        var previous
        annotations.forEach(annotation => {
            var clipId = annotation.id.split('/')[0] + '/' + annotation.in.toFixed(3)  + '-'+ annotation.out.toFixed(3)
            annotation.color1 = colors[clipId]
            if(previous) {
                previous.color2 = annotation.color1
            }
            previous = annotation
        })
        if (annotations.length) {
            annotations[annotations.length - 1].color2 = annotations[0].color1
        }
        return annotations
    })
}

function loadAnnotations(config) {
    if (config.item) {
        pandoraAPI('get', {id: config.item, keys: ['layers']}).then(response => {
            var annotations = response.data.layers[config.layer].filter(annotation => {
                return !(config.user && annotation.user != config.user)
            })
            loadClips(annotations).then(annotations => {
                config.annotations = annotations
                renderAnnotations(config)
            })
        })
    } else {
        pandoraAPI('getEdit', {id: config.edit, keys: []}).then(response => {
            var annotations = []
            response.data.clips.forEach(clip => {
                clip.layers[config.layer].forEach(annotation => {
                    if (config.user && annotation.user != config.user) {
                        return
                    }
                    annotation.title = clip.title
                    annotations.push(annotation)
                })
            })
            loadClips(annotations).then(annotations => {
                config.annotations = annotations
                renderAnnotations(config)
            })
        })
    }
}

config.layer = config.layer || layer

if (config.annotations) {
    renderAnnotations(config)
} else {
    loadAnnotatoins(config)
}