package ru.dbotthepony.mc.otm.config

import net.neoforged.fml.ModContainer
import net.neoforged.fml.config.ModConfig
import net.neoforged.neoforge.common.ModConfigSpec
import ru.dbotthepony.kommons.util.Delegate
import ru.dbotthepony.kommons.util.getValue
import ru.dbotthepony.mc.otm.OverdriveThatMatters
import ru.dbotthepony.mc.otm.core.math.Decimal
import ru.dbotthepony.mc.otm.core.math.defineDecimal
import ru.dbotthepony.mc.otm.core.util.WriteOnce

abstract class AbstractConfig(private val configName: String, private val type: ModConfig.Type = ModConfig.Type.SERVER) {
	var spec: ModConfigSpec by WriteOnce()
		private set
	protected val builder = ModConfigSpec.Builder()
	private var registered = false

	fun batteryValues(name: String, storage: Decimal, receive: Decimal, extract: Decimal = receive, initialBatteryLevel: Decimal = Decimal.ZERO): BatteryBalanceValues {
		builder.push(name)

		val obj = object : BatteryBalanceValues {
			override val energyCapacity: Decimal by builder.defineDecimal("ENERGY_CAPACITY", storage, minimum = Decimal.ONE)
			override val maxEnergyReceive: Decimal by builder.defineDecimal("MAX_RECEIVE", receive, minimum = Decimal.ONE)
			override val maxEnergyExtract: Decimal by builder.defineDecimal("MAX_EXTRACT", extract, minimum = Decimal.ONE)
			override val initialBatteryLevel: Decimal by builder.defineDecimal("INITIAL_BATTERY_LEVEL", initialBatteryLevel, minimum = Decimal.ZERO)
		}

		builder.pop()

		return obj
	}

	fun conciseValues(name: String, storage: Decimal, throughput: Decimal, configurator: ModConfigSpec.Builder.() -> Unit = {}): EnergyBalanceValues {
		builder.push(name)

		val obj = object : EnergyBalanceValues {
			override val energyCapacity: Decimal by builder.defineDecimal("ENERGY_CAPACITY", storage, minimum = Decimal.ONE)
			override val energyThroughput: Decimal by builder.defineDecimal("ENERGY_THROUGHPUT", throughput, minimum = Decimal.ONE)
		}

		configurator.invoke(builder)
		builder.pop()

		return obj
	}

	fun workerValues(
		name: String,
		energyStorage: Decimal,
		energyThroughput: Decimal,
		workTimeMultiplier: Double? = 1.0,
		energyConsumption: Decimal?,
		matterCapacity: Decimal? = null,
		maxExperience: Double? = null,
		configurator: ModConfigSpec.Builder.() -> Unit = {}
	): WorkerBalanceValues {
		builder.push(name)

		val obj = object : WorkerBalanceValues {
			override val energyCapacity: Decimal by builder.defineDecimal("ENERGY_CAPACITY", energyStorage, minimum = Decimal.ONE)
			override val energyThroughput: Decimal by builder.defineDecimal("ENERGY_THROUGHPUT", energyThroughput, minimum = Decimal.ONE)
			override val energyConsumption: Decimal by (if (energyConsumption == null) Delegate.Box(Decimal.ZERO) else builder.defineDecimal("ENERGY_CONSUMPTION", energyConsumption, minimum = Decimal.ONE))
			override val matterCapacity: Decimal by (if (matterCapacity == null) Delegate.Box(Decimal.ZERO) else builder.defineDecimal("MATTER_CAPACITY", matterCapacity, minimum = Decimal.ONE))
			override val workTimeMultiplier: Double by (if (workTimeMultiplier == null) Delegate.Box(1.0) else builder.defineInRange("WORK_TIME_MULTIPLIER", workTimeMultiplier, 0.0))
			override val maxExperienceStored: Double by (if (maxExperience == null) Delegate.Box(Double.POSITIVE_INFINITY) else builder.defineInRange("MAX_EXPERIENCE_STORED", maxExperience, 0.0))
		}

		configurator.invoke(builder)
		builder.pop()

		return obj
	}

	fun register(container: ModContainer) {
		check(!registered) { "Already registered config" }
		registered = true
		spec = builder.build()
		container.registerConfig(type, spec, "${OverdriveThatMatters.MOD_ID}-$configName.toml")
	}
}
