package com.nisemoe.nise.scheduler

import com.nisemoe.generated.tables.records.ScoresRecord
import com.nisemoe.generated.tables.references.BEATMAPS
import com.nisemoe.generated.tables.references.SCORES
import com.nisemoe.nise.database.UserService
import com.nisemoe.nise.integrations.CircleguardService
import com.nisemoe.nise.osu.OsuApi
import com.nisemoe.nise.osu.TokenService
import com.nisemoe.nise.service.AuthService
import com.nisemoe.nise.service.CacheService
import com.nisemoe.nise.service.CompressJudgements
import kotlinx.serialization.json.Json
import org.jooq.DSLContext
import org.junit.jupiter.api.Assertions.*
import org.junit.jupiter.api.Disabled
import org.junit.jupiter.api.Test
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.boot.test.mock.mockito.MockBean
import org.springframework.context.annotation.Import
import org.springframework.test.context.ActiveProfiles

@SpringBootTest
@ActiveProfiles("postgres")
@MockBean(GlobalCache::class, UserService::class)
@Disabled
class JudgementCompressionTest {

    private val logger = LoggerFactory.getLogger(javaClass)
    private val circleguardService = CircleguardService()
    private val compressJudgements = CompressJudgements()

    @Autowired
    private lateinit var dslContext: DSLContext

    @Test
    fun compressionIntegrityTest() {

        val scores = dslContext.select(SCORES.REPLAY, SCORES.BEATMAP_ID, SCORES.MODS, SCORES.REPLAY_ID)
            .from(SCORES)
            .where(SCORES.REPLAY.isNotNull)
            .limit(500)
            .fetchInto(ScoresRecord::class.java)

        val beatmapFile = dslContext.select(BEATMAPS.BEATMAP_FILE)
            .from(BEATMAPS)
            .where(BEATMAPS.BEATMAP_ID.eq(scores[0].beatmapId))
            .fetchOneInto(String::class.java)!!

        for(score in scores) {
            val result = score.replay?.let {
                this.circleguardService.processReplay(
                    replayData = it.decodeToString(),
                    beatmapData = beatmapFile,
                    mods = score.mods!!
                ).get()
            }

            if(result == null) {
                this.logger.warn("Failed to process replay for beatmap {} with mods {}", score.beatmapId, score.mods)
                continue
            }

            val compressedData = compressJudgements.serialize(result.judgements)

            this.logger.info("replay_id = {}", score.replayId)
            this.logger.info("JSON size: {} bytes", String.format("%,d", Json.encodeToString(CircleguardService.ReplayResponse.serializer(), result).length))
            this.logger.info("Compressed (Brotli) size: {} bytes", String.format("%,d", compressedData.size))

            val deserializedData = compressJudgements.deserialize(compressedData)

            for (entry in result.judgements) {
                assertEquals(entry.time, deserializedData[result.judgements.indexOf(entry)].time)
                assertEquals(entry.x, deserializedData[result.judgements.indexOf(entry)].x, 0.01)
                assertEquals(entry.y, deserializedData[result.judgements.indexOf(entry)].y, 0.01)
                assertEquals(entry.type, deserializedData[result.judgements.indexOf(entry)].type)
                assertEquals(entry.distance_center, deserializedData[result.judgements.indexOf(entry)].distance_center, 0.1)
                assertEquals(entry.distance_edge, deserializedData[result.judgements.indexOf(entry)].distance_edge, 0.1)
                assertEquals(entry.error, deserializedData[result.judgements.indexOf(entry)].error)
            }
        }

    }

}