/*
 *   This file is a part of the SteamWar software.
 *
 *   Copyright (C) 2025 SteamWar.de-Serverteam
 *
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU Affero General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *   GNU Affero General Public License for more details.
 *
 *   You should have received a copy of the GNU Affero General Public License
 *   along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

package de.steamwar.data

import io.ktor.client.*
import io.ktor.client.engine.java.*
import io.ktor.client.plugins.*
import io.ktor.client.plugins.contentnegotiation.*
import io.ktor.client.request.*
import io.ktor.client.statement.*
import io.ktor.serialization.kotlinx.json.*
import io.ktor.utils.io.jvm.javaio.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.Serializable
import kotlinx.serialization.cbor.Cbor
import kotlinx.serialization.decodeFromByteArray
import kotlinx.serialization.encodeToByteArray
import java.io.File
import java.time.Instant
import java.time.temporal.ChronoUnit

const val kCacheFolder: String = "skins"
val kCacheFolderFile: File = File(kCacheFolder)
const val kCacheConfigName: String = "cache.cbor"
val kCacheConfigFile: File = File(kCacheFolder, kCacheConfigName)

@Serializable
data class CacheConfig(val lastUpdate: MutableMap<String, Long>) {
    @OptIn(ExperimentalSerializationApi::class)
    companion object {
        private var config: CacheConfig = if (kCacheConfigFile.exists()) {
            kCacheConfigFile.inputStream().use {
                Cbor.decodeFromByteArray(it.readBytes())
            }
        } else {
            kCacheConfigFile.createNewFile()
            kCacheConfigFile.outputStream().use {
                it.write(Cbor.encodeToByteArray(CacheConfig(mutableMapOf())))
            }

            CacheConfig(mutableMapOf())
        }

        private fun save() {
            kCacheConfigFile.outputStream().use {
                it.write(Cbor.encodeToByteArray(config))
            }
        }

        fun update(uuid: String) {
            config.lastUpdate[uuid] = Instant.now().toEpochMilli()
            save()
        }

        fun isOutdated(uuid: String): Boolean {
            return config.lastUpdate[uuid]?.let {
                it < Instant.now().minus(1, ChronoUnit.DAYS).toEpochMilli()
            }
                ?: true
        }
    }
}

val client = HttpClient(Java) {
    install(ContentNegotiation) {
        json()
    }
    defaultRequest {
        header("User-Agent", "SteamWar/1.0")
    }
}

suspend fun getCachedSkin(uuid: String): Pair<File, Boolean> {
    val file = File(kCacheFolderFile, "$uuid.webp")
    if (file.exists()) {
        if (CacheConfig.isOutdated(uuid)) {
            val skin = client.get("https://vzge.me/bust/150/$uuid")
            skin.bodyAsChannel().copyTo(file.outputStream())

            CacheConfig.update(uuid)
            return file to false
        }
        return file to true
    }

    withContext(Dispatchers.IO) {
        file.createNewFile()
    }
    val skin = client.get("https://vzge.me/bust/150/$uuid")
    skin.bodyAsChannel().copyTo(file.outputStream())
    CacheConfig.update(uuid)
    return file to false
}
