package com.lanyuanxiaoyao.bookstore.controller

import cn.hutool.core.util.IdUtil
import com.lanyuanxiaoyao.bookstore.Book
import com.lanyuanxiaoyao.bookstore.BookRepository
import com.lanyuanxiaoyao.bookstore.Chapter
import com.lanyuanxiaoyao.bookstore.ChapterRepository
import com.lanyuanxiaoyao.bookstore.Line
import com.lanyuanxiaoyao.bookstore.LineRepository
import com.lanyuanxiaoyao.bookstore.PageResponse
import com.lanyuanxiaoyao.bookstore.SingleResponse
import jakarta.annotation.Resource
import jakarta.transaction.Transactional
import org.slf4j.LoggerFactory
import org.springframework.data.domain.PageRequest
import org.springframework.data.domain.Sort
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.bind.annotation.RestController

@RestController
@RequestMapping("chapter")
class ChapterController {
    private val log = LoggerFactory.getLogger(javaClass)

    @Resource
    private lateinit var bookRepository: BookRepository

    @Resource
    private lateinit var chapterRepository: ChapterRepository

    @Resource
    private lateinit var lineRepository: LineRepository

    @GetMapping("list/{bookId}")
    fun list(
        @PathVariable("bookId") bookId: String,
        @RequestParam("page", defaultValue = "1") page: Int,
        @RequestParam("size", defaultValue = "10") size: Int
    ): PageResponse<ViewItem> {
        val pageable = chapterRepository.findAll({ root, _, builder ->
            builder.equal(root.get<Book>("book").get<String>("bookId"), bookId)
        }, PageRequest.of(0.coerceAtLeast(page - 1), size))
        return PageResponse(
            pageable.content.map { ViewItem(it) },
            pageable.totalElements,
        )
    }

    @Transactional
    @PostMapping("save/{bookId}")
    fun save(@PathVariable("bookId") bookId: String, @RequestBody item: ViewItem) {
        val book = bookRepository.findById(bookId).orElseThrow()
        chapterRepository.save(
            Chapter(
                chapterId = item.chapterId ?: IdUtil.fastSimpleUUID(),
                name = item.name,
                sequence = item.sequence,
                description = item.description,
                book = book,
            )
        )
    }

    @Transactional
    @PostMapping("import/{chapterId}")
    fun import(@PathVariable("chapterId") chapterId: String, @RequestBody item: ImportItem) {
        val chapter = chapterRepository.findById(chapterId).orElseThrow()
        var startIndex = chapter.content.size.toLong()
        if (item.override) {
            lineRepository.deleteAllInBatch(chapter.content)
            startIndex = 0
        }
        chapter.content = item.text
            .split("\n")
            .mapIndexed { index, line ->
                Line(
                    lineId = IdUtil.fastSimpleUUID(),
                    sequence = startIndex + index,
                    text = line.trim(),
                    chapter = chapter,
                )
            }
            .toMutableSet()
        chapterRepository.save(chapter)
    }

    @GetMapping("detail/{chapterId}")
    fun detail(@PathVariable("chapterId") chapterId: String): ViewItem {
        return chapterRepository.findById(chapterId).orElseThrow().let { ViewItem(it) }
    }

    @GetMapping("show/{chapterId}")
    fun show(@PathVariable("chapterId") chapterId: String): SingleResponse<String> {
        return SingleResponse(
            lineRepository
                .findAll({ root, _, builder ->
                    builder.equal(root.get<Chapter>("chapter").get<String>("chapterId"), chapterId)
                }, Sort.by(Sort.Direction.DESC, "sequence"))
                .joinToString("\n") { "<p>${it.text}</p>" }
        )
    }

    @Transactional
    @GetMapping("remove/{chapterId}")
    fun remove(@PathVariable("chapterId") chapterId: String) {
        chapterRepository.deleteById(chapterId)
    }

    data class ViewItem(
        val chapterId: String?,
        val name: String?,
        val sequence: Int,
        val description: String?,
    ) {
        constructor(chapter: Chapter) : this(
            chapter.chapterId,
            chapter.name,
            chapter.sequence,
            chapter.description,
        )
    }

    data class ImportItem(
        val override: Boolean = false,
        val text: String
    )
}