package kr.lunaticbum.back.lun.model

import kr.lunaticbum.back.lun.repository.PostHistoryRepository
import kr.lunaticbum.back.lun.repository.PostRepository
import org.springframework.data.domain.Sort
import org.springframework.data.mongodb.core.ReactiveMongoTemplate
import org.springframework.data.mongodb.core.aggregation.Aggregation
import org.springframework.data.mongodb.core.query.Query
import org.springframework.data.mongodb.core.aggregation.Aggregation.*
import org.springframework.stereotype.Service
import reactor.core.publisher.Flux
import reactor.core.publisher.Mono

// 마이그레이션 결과 리포트를 위한 데이터 클래스
data class MigrationReport(
    val processedGroups: Int,
    val latestPostsMigrated: Int,
    val historyPostsMigrated: Int,
    val errors: List<String>
)

@Service
class MigrationService(
    private val mongoTemplate: ReactiveMongoTemplate,
    private val postRepository: PostRepository, // 새 Post Repository
    private val postHistoryRepository: PostHistoryRepository // 새 PostHistory Repository
) {
    // Mono<MigrationReport>를 반환하여 비동기 작업의 결과를 컨트롤러에 전달
    fun migratePosts(): Mono<MigrationReport> {
        // 1. originId가 null이 아닌 문서만 대상으로 그룹화
        val aggregation = newAggregation(
            Post::class.java,
            sort(Sort.Direction.DESC, "modifyTime"),
            group("originId")
                .push("$$ROOT").`as`("versions")
        )

        return mongoTemplate.aggregate(aggregation, "Post", Map::class.java)
            .flatMap { versionGroup ->
                @Suppress("UNCHECKED_CAST")
                val versions = versionGroup["versions"] as? List<Map<String, Any>> ?: return@flatMap Mono.empty<Void>()

                if (versions.isEmpty()) {
                    return@flatMap Mono.empty<Pair<Int, Int>>()
                }

                // 3. 첫 번째 항목이 최신 버전, 나머지가 과거 버전
                // FIX 1: Changed .first to .first()
                val latestVersionMap = versions.first()
                val oldVersionsMaps = versions.drop(1)

                // 4. 최신 버전을 새 Post 객체로 변환하고 저장
                val newPost = mapToPost(latestVersionMap).apply {
                    originId = null
                }

                postRepository.save(newPost)
                    .flatMap { savedPost ->
                        // 5. 과거 버전들을 PostHistory 객체로 변환하여 저장
                        val historyFlux = Flux.fromIterable(oldVersionsMaps)
                            .map { oldVersionMap ->
                                mapToHistory(oldVersionMap, savedPost.id!!)
                            }
                            .flatMap { history ->
                                postHistoryRepository.save(history)
                            }
                        historyFlux.then(Mono.just(Pair(1, oldVersionsMaps.size)))
                    }
            }
            .reduce(Pair(0, 0)) { acc, pair ->
                Pair(acc.first + (pair as Pair<Int,Int>).first, acc.second + pair.second)
            }
            .map { (latestCount, historyCount) ->
                MigrationReport(
                    processedGroups = latestCount,
                    latestPostsMigrated = latestCount,
                    historyPostsMigrated = historyCount,
                    errors = emptyList()
                )
            }
            .defaultIfEmpty(MigrationReport(0, 0, 0, listOf("No data to migrate.")))
    }

    // Map을 Post 객체로 변환하는 헬퍼 함수
    private fun mapToPost(map: Map<String, Any>): Post = Post(
        id = map["_id"]?.toString(),
        originId = map["originId"] as? String, // 마이그레이션 중에는 originId가 필요
        title = map["title"] as? String,
        content = map["content"] as? String,
        category = map["category"] as? String,
        tags = map["tags"] as? String,
        writer = map["writer"] as? String,
        writeTime = (map["writeTime"] as? Number)?.toLong() ?: 0L,
        posting = map["posting"] as? Boolean ?: false,
        modifyTime = (map["modifyTime"] as? Number)?.toLong() ?: 0L
        // ... Post의 모든 필드를 안전하게 변환 ...
    )

    // Map을 PostHistory 객체로 변환하는 헬퍼 함수
    private fun mapToHistory(map: Map<String, Any>, newPostId: String): PostHistory = PostHistory(
        postId = newPostId,
        title = map["title"] as? String,
        content = map["content"] as? String,
        category = map["category"] as? String,
        tags = map["tags"] as? String,
        writer = map["writer"] as? String,
        writeTime = (map["writeTime"] as? Number)?.toLong() ?: 0L,
        posting = map["posting"] as? Boolean ?: false,
        modifyTime = (map["modifyTime"] as? Number)?.toLong() ?: 0L
        // ... PostHistory의 모든 필드를 안전하게 변환 ...
    )
}