package app.furmeet.events.system.schedule.managers

import android.content.Context
import android.content.res.Resources
import app.furmeet.events.system.helper.joinFile
import app.furmeet.events.system.helper.lastPathPart
import java.io.File
import java.io.InputStream

class OnlineCacheManager(context: Context) : CacheManager() {
    internal val cacheLocation = File(context.filesDir, "cache_data")
            .also {
                if (!it.isDirectory) {
                    it.mkdirs()
                }
            }
    private val cacheStamps = File(context.filesDir, "cache_stamps")
            .also {
                if (!it.isDirectory) {
                    it.mkdirs()
                }
            }
    override val goesOnline = true
    override val preloaded = false

    init {
        sanitize()
    }

    override fun getStamp(file: String): String? {
        val cachedFile = cacheLocation.joinFile(file)
        val cachedData = cacheStamps.joinFile(file)
        if (!cachedFile.exists() || !cachedData.exists()) return null
        return cachedData.readText().let { if (it.isBlank()) null else it }
    }

    override operator fun get(file: String): Pair<InputStream, String>? {
        val cachedFile = cacheLocation.joinFile(file)
        val cachedData = cacheStamps.joinFile(file)
        if (!cachedFile.exists() || !cachedData.exists()) return null
        val stamp = cachedData.readText()
        if (stamp.isBlank()) return null
        return Pair(
                cachedFile.inputStream(),
                stamp
        )
    }

    override fun fallbackGet(file: String): Pair<InputStream, String>? = get(file)

    override operator fun set(file: String, requestResult: Pair<ByteArray, String>) {
        if (requestResult.second.isBlank()) return
        val cachedFile = cacheLocation.joinFile(file)
        val cachedData = cacheStamps.joinFile(file)
        cachedData.writeText(requestResult.second)
        cachedFile.writeBytes(requestResult.first)
    }

    override fun delete(file: String): Boolean {
        val cachedFile = cacheLocation.joinFile(file)
        val cachedData = cacheStamps.joinFile(file)
        return (if (cachedFile.exists()) cachedFile.delete() else false) and (if (cachedData.exists()) cachedData.delete() else false)
    }

    override fun sanitize(): Int {
        val datas = (cacheLocation.listFiles()
                ?: arrayOf()).toList().map { it.absolutePath.lastPathPart() }
        val stmps = (cacheStamps.listFiles()
                ?: arrayOf()).toList().map { it.absolutePath.lastPathPart() }
        val unreliableEntries = (datas - stmps) + (stmps - datas)
        return unreliableEntries.map { delete(it) }.size
    }

    override val files: Set<String>
        get() {
            val datas = (cacheLocation.listFiles()
                    ?: arrayOf()).toList().map { it.absolutePath.lastPathPart() }
            val stmps = (cacheStamps.listFiles()
                    ?: arrayOf()).toList().map { it.absolutePath.lastPathPart() }
            return datas.intersect(stmps)
        }

    override fun getFileFor(asset: String): File {
        val retFile = cacheLocation.joinFile(asset.lastPathPart())
        if (!retFile.exists())
            throw Resources.NotFoundException("Unavailable asset: $asset")
        return retFile
    }
}