package kr.lunaticbum.back.lun.model

import lombok.AllArgsConstructor
import lombok.Data
import lombok.NoArgsConstructor
import org.springframework.data.annotation.Id
import org.springframework.data.mongodb.core.index.Indexed
import org.springframework.data.mongodb.core.mapping.Document
import org.springframework.data.mongodb.repository.ReactiveMongoRepository
import org.springframework.security.web.authentication.rememberme.PersistentRememberMeToken
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository
import org.springframework.stereotype.Component
import org.springframework.stereotype.Repository
import reactor.core.publisher.Flux
import reactor.core.publisher.Mono
import java.time.LocalDateTime
import java.util.*


@Data
@NoArgsConstructor
@AllArgsConstructor
@Document(collection = "TokenData")
class TokenData {
    @Indexed(name = "ttl",expireAfterSeconds = 0)
    var expireAt: LocalDateTime? = null

    @Id
    var tokenKey : String? = null

    var refreshToken : String? = null

    constructor(tokenKey: String?, refreshToken: String?) {
        this.expireAt = LocalDateTime.now().plusSeconds(500)
        this.tokenKey = tokenKey
        this.refreshToken = refreshToken
    }
}


@Repository
interface TokenDataRepository : ReactiveMongoRepository<TokenData, String> {
    fun findBytokenKey(tokenKey: String): Mono<TokenData>
    fun deleteBytokenKey(tokenKey: String)
}
interface PersistentTokenRepository {
    fun createNewToken(token: PersistentRememberMeToken)
    fun updateToken(series: String, tokenValue: String, lastUsed: Date)
    fun getTokenForSeries(seriesId: String): PersistentRememberMeToken?
    fun removeUserTokens(username: String)
}

@Data
@NoArgsConstructor
@AllArgsConstructor
@Document(collection = "persistent_logins")
data class PersistentLogin(
    @Id val series: String,
    val username: String,
    val tokenValue: String,
    val lastUsed: Date
)

interface PersistentLoginRepository : ReactiveMongoRepository<PersistentLogin, String> {
    fun findByUsername(username: String): Flux<PersistentLogin>
}
@Component
class MongoPersistentTokenRepository (
    private val repository: PersistentLoginRepository
) : PersistentTokenRepository {

    override fun createNewToken(token: PersistentRememberMeToken) {
        val persistentLogin = PersistentLogin(
            series = token.series,
            username = token.username,
            tokenValue = token.tokenValue,
            lastUsed = token.date
        )
        // [수정] .block() 대신 .subscribe()를 사용하여 비동기 실행
        repository.save(persistentLogin).subscribe()
        println("CALLED rememberMeServices: createNewToken")
    }

    override fun updateToken(series: String, tokenValue: String, lastUsed: Date) {
        // [수정] .block() 대신 .flatMap과 .subscribe()를 사용
        repository.findById(series).flatMap { login ->
            val updated = login.copy(tokenValue = tokenValue, lastUsed = lastUsed)
            repository.save(updated)
        }.subscribe()
        println("CALLED rememberMeServices: updateToken")
    }

    override fun getTokenForSeries(seriesId: String): PersistentRememberMeToken? {
        // [주의] 이 인터페이스 메소드는 동기(blocking) 반환을 요구하므로,
        // 어쩔 수 없이 .block()을 사용해야 합니다. 하지만,
        // 자동 로그인은 메인 요청 흐름에 덜 치명적이므로 이 부분은 유지합니다.
        // 근본적인 해결을 위해서는 Spring Security의 ReactivePersistentTokenRepository 사용이 필요합니다.
        val login = repository.findById(seriesId).block()
        return login?.let {
            println("CALLED rememberMeServices: getTokenForSeries")
            PersistentRememberMeToken(it.username, it.series, it.tokenValue, it.lastUsed)
        }
    }

    override fun removeUserTokens(username: String) {
        // [수정] .block() 대신 .flatMap과 .subscribe()를 사용
        repository.findByUsername(username)
            .collectList()
            .flatMap { tokens ->
                if (tokens.isNotEmpty()) {
                    repository.deleteAll(tokens)
                } else {
                    Mono.empty()
                }
            }.subscribe()
        println("CALLED rememberMeServices: removeUserTokens")
    }
}
