/*
 * This file is part of LiquidBounce (https://github.com/CCBlueX/LiquidBounce)
 *
 * Copyright (c) 2015 - 2026 CCBlueX
 *
 * LiquidBounce is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * LiquidBounce 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with LiquidBounce. If not, see <https://www.gnu.org/licenses/>.
 */
package net.ccbluex.liquidbounce.deeplearn

import ai.djl.engine.Engine
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import net.ccbluex.liquidbounce.config.ConfigSystem.rootFolder
import net.ccbluex.liquidbounce.integration.task.type.Task
import net.ccbluex.liquidbounce.utils.client.clientLogger
import java.util.Locale

object DeepLearningEngine {

    private val logger = clientLogger("AI")

    @Volatile
    var isInitialized = false
        private set

    private val deepLearningFolder = rootFolder.resolve("deeplearning").apply {
        mkdirs()
    }

    val djlCacheFolder = deepLearningFolder.resolve("djl").apply {
        mkdirs()
    }

    val enginesCacheFolder = deepLearningFolder.resolve("engines").apply {
        mkdirs()
    }

    val modelsFolder = deepLearningFolder.resolve("models").apply {
        mkdirs()
    }

    init {
        System.setProperty("DJL_CACHE_DIR", djlCacheFolder.absolutePath)
        System.setProperty("ENGINE_CACHE_DIR", enginesCacheFolder.absolutePath)

        // Disable tracking of DJL
        System.setProperty("OPT_OUT_TRACKING", "true")

        // Set the default engine to PyTorch
        System.setProperty("DJL_DEFAULT_ENGINE", "PyTorch")
        // Enforce CPU pytorch flavor (CUDA often conflicts with NVIDIA CUDA and is too large for our use case)
        System.setProperty("PYTORCH_FLAVOR", "cpu")

        ModelManager
    }

    @JvmStatic
    @Volatile
    var task: Task? = null

    /**
     * DJL will automatically download engine libraries, as soon we call [Engine.getInstance()],
     * for the platform we are running on.
     *
     * This should be done here,
     * as we want to make sure that the libraries are downloaded
     * before we try to load any models.
     */
    suspend fun init(task: Task) {
        this.task = task
        isInitialized = false

        logger.info("Initializing engine...")
        val engine = withContext(Dispatchers.IO) {
            Engine.getInstance()
        }
        val name = engine.engineName
        val version = engine.version
        val deviceType = engine.defaultDevice().deviceType.uppercase(Locale.ENGLISH)
        logger.info("Using deep learning engine $name $version on $deviceType.")
    }

    internal fun markInitialized() {
        isInitialized = true
        this.task = null
    }

    internal fun markUnavailable() {
        isInitialized = false
        this.task = null
    }

}
