package com.nisemoe.nise.rss

import com.nisemoe.generated.tables.references.BEATMAPS
import com.nisemoe.generated.tables.references.SCORES
import com.nisemoe.generated.tables.references.SCORES_SIMILARITY
import com.nisemoe.generated.tables.references.USERS
import com.nisemoe.nise.database.ScoreService
import org.jooq.DSLContext
import org.springframework.stereotype.Service
import java.time.ZoneOffset
import java.time.format.DateTimeFormatter
import java.util.*

@Service
class RssService(
    private val dslContext: DSLContext
) {

    fun generateFeed(): RssFeed {
        val items = mutableListOf<RssFeedController.IntermeriaryFeedItem>()
        addSuspiciousScores(items)
        addStolenReplays(items)

        // Sort by date DESC
        items.sortByDescending { it.pubDate }

        // Limit to 50
        items.subList(0, items.size.coerceAtMost(50))

        val channel = Channel(
            title = "nise.moe's feed and sneed",
            link = "https://nise.moe/rss",
            description = "Feed of *sus* scores for osu!std - /nise.moe/",
            lastBuildDate = Date().toInstant().atZone(ZoneOffset.UTC).format(DateTimeFormatter.RFC_1123_DATE_TIME),
            item = items.map {
                Item(
                    title = it.title,
                    guid = it.guid,
                    link = it.link,
                    description = it.description,
                    pubDate = it.pubDate.format(DateTimeFormatter.RFC_1123_DATE_TIME)
                )

            },
            atomLink = AtomLink(href = "https://nise.moe/rss.xml")
        )

        return RssFeed(channel = channel)
    }

    private fun addStolenReplays(items: MutableList<RssFeedController.IntermeriaryFeedItem>) {
        val replays = dslContext
            .select()
            .from(SCORES_SIMILARITY)
            .join(ScoreService.osuScoreAlias1).on(ScoreService.osuScoreAlias1.REPLAY_ID.eq(SCORES_SIMILARITY.REPLAY_ID_1))
            .join(ScoreService.osuUserAlias1).on(ScoreService.osuScoreAlias1.USER_ID.eq(ScoreService.osuUserAlias1.USER_ID))
            .leftJoin(ScoreService.osuScoreAlias2).on(ScoreService.osuScoreAlias2.REPLAY_ID.eq(SCORES_SIMILARITY.REPLAY_ID_2))
            .leftJoin(ScoreService.osuUserAlias2).on(ScoreService.osuScoreAlias2.USER_ID.eq(ScoreService.osuUserAlias2.USER_ID))
            .join(BEATMAPS).on(BEATMAPS.BEATMAP_ID.eq(ScoreService.osuScoreAlias1.BEATMAP_ID))
            .where(SCORES_SIMILARITY.SIMILARITY.lt(10.0))
            .and(ScoreService.osuScoreAlias1.IS_BANNED.eq(false))
            .and(ScoreService.osuScoreAlias2.IS_BANNED.eq(false))
            .orderBy(SCORES_SIMILARITY.CREATED_AT.desc())
            .limit(25)
            .fetch()

        for (result in replays) {
            val score1 = result.into(ScoreService.osuScoreAlias1)
            val user1 = result.into(ScoreService.osuUserAlias1)
            val score2 = result.into(ScoreService.osuScoreAlias2)
            val user2 = result.into(ScoreService.osuUserAlias2)
            val beatmap = result.into(BEATMAPS)

            if(score1.addedAt != null) {
                val item = RssFeedController.IntermeriaryFeedItem(
                    title = "Possible stolen replay",
                    guid = "https://nise.moe/p/${score1.replayId}/${score2.replayId}",
                    link = "https://nise.moe/p/${score1.replayId}/${score2.replayId}",
                    description = "Similarity: ${result[SCORES_SIMILARITY.SIMILARITY]}%\n" +
                            "Replay by ${user1.username} on ${beatmap.artist} - ${beatmap.title} [${beatmap.version}] (${beatmap.starRating} stars)\n" +
                            "Replay by ${user2.username} on ${beatmap.artist} - ${beatmap.title} [${beatmap.version}] (${beatmap.starRating} stars)",
                    pubDate = score1.addedAt!!
                )
                items.add(item)
            }
        }
    }

    private fun addSuspiciousScores(items: MutableList<RssFeedController.IntermeriaryFeedItem>) {
        val suspiciousScores = dslContext.select(
            USERS.USERNAME,
            SCORES.REPLAY_ID,
            SCORES.DATE,
            BEATMAPS.ARTIST,
            BEATMAPS.TITLE,
            BEATMAPS.VERSION,
            BEATMAPS.STAR_RATING
        )
            .from(SCORES)
            .join(USERS).on(SCORES.USER_ID.eq(USERS.USER_ID))
            .join(BEATMAPS).on(SCORES.BEATMAP_ID.eq(BEATMAPS.BEATMAP_ID))
            .where(SCORES.UR.lessOrEqual(25.0))
            .and(SCORES.IS_BANNED.eq(false))
            .orderBy(SCORES.ADDED_AT.desc())
            .limit(25)
            .fetch()

        for (result in suspiciousScores) {
            val score = result.into(SCORES)
            val user = result.into(USERS)
            val beatmap = result.into(BEATMAPS)

            if(score.addedAt != null) {
                val item = RssFeedController.IntermeriaryFeedItem(
                    title = "Suspicious score by ${user.username}",
                    guid = "https://nise.moe/s/${score.replayId}",
                    link = "https://nise.moe/s/${score.replayId}",
                    description = "New score by ${user.username} on ${beatmap.artist} - ${beatmap.title} [${beatmap.version}] (${beatmap.starRating} stars)",
                    pubDate = score.addedAt!!
                )
                items.add(item)
            }

        }
    }

}