package inn.ocsf.bee.freigeld.core.demo

import inn.ocsf.bee.freigeld.core.model.BankAccount
import inn.ocsf.bee.freigeld.core.model.CentralBank
import inn.ocsf.bee.freigeld.core.model.GlobalEmitter
import inn.ocsf.bee.freigeld.core.model.GlobalWorld
import inn.ocsf.bee.freigeld.core.service.TicketService
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Service
import javax.annotation.PostConstruct
import javax.inject.Inject

@Service
class DemoInMem {

    @Autowired
    private lateinit var world: GlobalWorld

    @Autowired
    private lateinit var emitter: GlobalEmitter

    @Autowired
    private lateinit var bank: CentralBank

    private val log = LoggerFactory.getLogger(javaClass)

    @Inject
    private lateinit var ticketService: TicketService

    @PostConstruct
    fun init() {
        /*emitter.emit(10000, CoinValue.one)
        emitter.emit(5000, CoinValue.three)
        emitter.emit(2000, CoinValue.five)
        emitter.emit(1000, CoinValue.ten)
        emitter.emit(500, CoinValue.quarter)
        emitter.emit(100, CoinValue.half)
        emitter.emit(50, CoinValue.full)
        emitter.emit(25, CoinValue.bi)
        emitter.emit(10, CoinValue.mega)
*/
        /*CoinUtils.avaiues.flatMap { it.value }.forEach { c ->
            emitter.emit((10..40L).random(), c.first, c.second)
        }
        //bank.exchange(bank.getSelfAccount(), emitter, 2_300_000)

        (0 until 100).map {
            val newHuman: NaturalPerson = PersonData.NaturalPersonImpl(Nomen.randomName())
            val oldHuman = world.getPersonByIdentity(PersonIdentityFullName(newHuman.fullName))
            if (oldHuman != null) {
                oldHuman as NaturalPerson
            } else {
                world.addPerson(newHuman)
                world.setPersonIdentity(newHuman, PersonIdentityFullName(newHuman.fullName))
                newHuman
            }
        }.forEach { log.info("human ${it.fullName} created") }

        world.getPersonIds().map { bank.addAccount(it) }.forEach {
            bank.exchange(it, bank.getSelfAccount(), 1_200 + (500 * Math.random()).roundToLong())
                    .thenRun({ log.info("exchange ok") })
                    .exceptionally({ log.error("exchange error"); null })
        }
*/
    }

    private fun doRand0() {
        val personIds = world.getPersonIds()
        val fromPerson = personIds.subtract(setOf(bank.id)).random()
        val toPerson = personIds.subtract(setOf(bank.id, fromPerson)).random()
        val fromAccount = bank.getAccounts(fromPerson).first()
        val toAccout = bank.getAccounts(toPerson).first()
        val dir = if (fromAccount.overall >= toAccout.overall) fromAccount to toAccout else toAccout to fromAccount
        val x = Math.min(Math.round(dir.first.overall * 0.9), Math.max(0, Math.round(dir.first.overall * Math.random())))
        bank.exchange(dir.second, dir.first, x, null).thenRun({ log.info("exchange ok") }).exceptionally({ log.error("exchange error ${it.message}"); null })
    }

    //@Scheduled(initialDelay = 30 * 1000L, fixedDelay = 2000L)
    fun tick() {
        doRand0()
        log.info("tick")
    }

    //@Scheduled(initialDelay = 60 * 1000L, fixedDelay = 60 * 1000L)
    fun calc() {
        //ticketService.offerAfter(GlobalEmitterImpl.emitterTicketChannel, Date.from(LocalDateTime.now().plusMinutes(5).atZone(ZoneId.systemDefault()).toInstant()), object : Ticket(UUID.randomUUID()) {})
        log.info("calc")
    }
}

fun CentralBank.getSelfAccount(): BankAccount {
    return this.getAccounts(this.id).first()
}


