package com.nisemoe.nise.controller

import com.nisemoe.generated.tables.references.USERS
import com.nisemoe.generated.tables.references.USER_FOLLOWS
import com.nisemoe.nise.service.AuthService
import jakarta.validation.Valid
import jakarta.validation.constraints.Size
import org.jooq.DSLContext
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.DeleteMapping
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.PutMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RestController
import java.time.OffsetDateTime

@RestController
class FollowsController(
    private val dslContext: DSLContext,
    private val authService: AuthService
) {

    companion object {

        const val MAX_FOLLOWS_PER_USER = 1000

    }

    data class FollowsBanStatusResponse(
        val follows: List<FollowsBanStatusEntry>
    )

    data class FollowsBanStatusEntry(
        val userId: Long,
        val username: String,
        val secondsPlayed: Long?,
        val pp: Double?,
        val rank: Long?,
        val isBanned: Boolean?,
        val approximateBanTime: OffsetDateTime?,
        val lastUpdate: OffsetDateTime?
    )

    @GetMapping("follows")
    fun getFollowsBanStatus(): ResponseEntity<FollowsBanStatusResponse> {
        authService.getCurrentUser().userId
        val follows = dslContext.select(
            USERS.USER_ID,
            USERS.USERNAME,
            USERS.SECONDS_PLAYED,
            USERS.IS_BANNED,
            USERS.PP_RAW,
            USERS.RANK,
            USERS.SYS_LAST_UPDATE,
            USERS.APPROX_BAN_DATE
        )
            .from(USER_FOLLOWS)
            .join(USERS).on(USER_FOLLOWS.FOLLOWS_USER_ID.eq(USERS.USER_ID))
            .where(USER_FOLLOWS.USER_ID.eq(authService.getCurrentUser().userId))
            .fetch()
            .map {
                FollowsBanStatusEntry(
                    it[USERS.USER_ID]!!,
                    it[USERS.USERNAME]!!,
                    it[USERS.SECONDS_PLAYED],
                    it[USERS.PP_RAW],
                    it[USERS.RANK],
                    it[USERS.IS_BANNED],
                    it[USERS.APPROX_BAN_DATE],
                    it[USERS.SYS_LAST_UPDATE]
                )
            }

        return ResponseEntity.ok(FollowsBanStatusResponse(follows))
    }

    // TODO: CSRF

    @GetMapping("follows/{followsUserId}")
    fun getFollowsBanStatusByUserId(@PathVariable followsUserId: Long): ResponseEntity<FollowsBanStatusEntry> {
        val userId = authService.getCurrentUser().userId

        val follows = dslContext.select(
            USERS.USER_ID,
            USERS.USERNAME,
            USERS.SECONDS_PLAYED,
            USERS.IS_BANNED,
            USERS.PP_RAW,
            USERS.RANK,
            USERS.SYS_LAST_UPDATE,
            USERS.APPROX_BAN_DATE
        )
            .from(USER_FOLLOWS)
            .join(USERS).on(USER_FOLLOWS.FOLLOWS_USER_ID.eq(USERS.USER_ID))
            .where(USER_FOLLOWS.USER_ID.eq(userId).and(USER_FOLLOWS.FOLLOWS_USER_ID.eq(followsUserId)))
            .fetch()
            .map {
                FollowsBanStatusEntry(
                    it[USERS.USER_ID]!!,
                    it[USERS.USERNAME]!!,
                    it[USERS.SECONDS_PLAYED],
                    it[USERS.PP_RAW],
                    it[USERS.RANK],
                    it[USERS.IS_BANNED],
                    it[USERS.APPROX_BAN_DATE],
                    it[USERS.SYS_LAST_UPDATE]
                )
            }

        return if(follows.isEmpty()) {
            ResponseEntity.status(404).build()
        } else {
            ResponseEntity.ok(follows.first())
        }
    }

    data class UpdateFollowsBanStatusRequest(
        @Valid @field:Size(max = 200)
        val userIds: List<Long>,
    )

    @PutMapping("follows")
    fun updateFollowsBanStatus(@RequestBody @Valid request: UpdateFollowsBanStatusRequest): ResponseEntity<Void> {
        // Check if the user already has MAX_FOLLOWS_PER_USER or more
        if(dslContext.fetchCount(USER_FOLLOWS, USER_FOLLOWS.USER_ID.eq(authService.getCurrentUser().userId)) >= MAX_FOLLOWS_PER_USER) {
            return ResponseEntity.status(400).build()
        }

        val userId = authService.getCurrentUser().userId

        for(userIdToBan in request.userIds) {
            dslContext.insertInto(USER_FOLLOWS)
                .columns(USER_FOLLOWS.USER_ID, USER_FOLLOWS.FOLLOWS_USER_ID)
                .values(userId, userIdToBan)
                .onDuplicateKeyIgnore()
                .execute()
        }

        return ResponseEntity.ok().build()
    }

    data class DeleteFollowsBanStatusRequest(
        @Valid @field:Size(max = 200)
        val userIds: List<Long>,
    )

    @DeleteMapping("follows")
    fun deleteFollowsBanStatus(@RequestBody @Valid request: DeleteFollowsBanStatusRequest): ResponseEntity<Void> {
        val userId = authService.getCurrentUser().userId

        for(userIdToUnban in request.userIds) {
            dslContext.deleteFrom(USER_FOLLOWS)
                .where(USER_FOLLOWS.USER_ID.eq(userId))
                .and(USER_FOLLOWS.FOLLOWS_USER_ID.eq(userIdToUnban))
                .execute()
        }

        return ResponseEntity.ok().build()
    }

}