const app = window.app ??= {}
const view = window.view ??= {}

import * as device from 'device'
import Store from 'store'

// TODO: decouple from app.browser and add loading bar

export let covers

export const Start = async () => {
    covers = await Store.Open('cover', 'data')
}

export const Init = async () => {
    view.loadingStatus = document.getElementById('loading-status')
    app.trackCount = 0
    app.index = await Entries()
}

export const Entries = async (hHandle, eParent) => {
    let dirE = await device.Entries(hHandle)
    let out = []

    for(let [ n, h ] of dirE) {
        let e = await Create(n, h, eParent)
        if(e != undefined) {
            out.push(e)
            displayTrackFound(e)
        }
    }

    return out
}

export const displayTrackFound = (entry) => {
    app.trackCount++
    view.loadingStatus.innerText = `${entry.handle.name}\n(${app.trackCount})`
}

export const trackFiletypes = [
    '.mp3',
    '.ogg',
    '.wav',
    '.flac'
]

export const Create = async (sName, hHandle, eParent) => {
    let e = {
        handle: hHandle
    }

    if(eParent) {
        e.parent = eParent
    }

    switch(hHandle.kind) {
        case 'directory':
            e.entries = await Entries(hHandle, e)
            e.name = sName
        break

        case 'file':
            let ext = sName.slice(sName.lastIndexOf('.'))
            if(trackFiletypes.includes(ext)) {
                await Track(e)
            } else {
                return
            }
    }

    e.order = e.trackNumber ?? 0

    return e
}

const Track = async e => {
    let md = await Metadata(e)

    e.album = md.album
	e.name = md.title
    e.artist = md.artist ?? "Unknown Artist"
    e.trackNumber = md.track ? parseInt(md.track) : Infinity
    e.lyrics = md.lyrics?.lyrics && new Map([ [ 0, md.lyrics?.lyrics ] ])
    e.coverId = md.picture && await IndexCover(md.picture)
}

export const IndexCover = async ({ format, data }) => {
    let id = format + '-' + data.length

    // TODO: don't get, just check if has
    let c = await covers.Get(id)
        .catch(err => {})
    if(c == null) {
        c = new Blob([ new Uint8Array(data) ], { type: format })
        await covers.Set(id, c)
    }
    return id
}

export const GetCover = (eTrack) => {
    return covers.Get(eTrack.coverId)
}

const Metadata = async e => {
    let d = await device.Open(e.handle).then(mediaTags)
        .catch(e => console.error(e))

    if(!d) {
        return /((?<track>\d+)\s+)?((?<artist>.+)-\s*)?\s*(?<title>.+)\s*\.\w+/
            .exec(e.handle.name)
            .groups
    } else {
        return d.tags
    }
}

const mediaTags = blob => new Promise((resolve, reject) => {
	jsmediatags.read(blob, {
		onSuccess(tags) {
			resolve(tags)
		},
		onError(err) {
			reject(err)
		}
	})
})