@file:Suppress("FunctionName")

package com.lanyuanxiaoyao.bookstore

import jakarta.persistence.CascadeType
import jakarta.persistence.Column
import jakarta.persistence.ConstraintMode
import jakarta.persistence.ElementCollection
import jakarta.persistence.Entity
import jakarta.persistence.FetchType
import jakarta.persistence.ForeignKey
import jakarta.persistence.Id
import jakarta.persistence.JoinColumn
import jakarta.persistence.Lob
import jakarta.persistence.ManyToOne
import jakarta.persistence.NamedAttributeNode
import jakarta.persistence.NamedEntityGraph
import jakarta.persistence.OneToMany
import org.hibernate.annotations.DynamicUpdate
import org.springframework.data.jpa.repository.EntityGraph
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.data.jpa.repository.JpaSpecificationExecutor
import org.springframework.data.jpa.repository.Query
import org.springframework.stereotype.Repository

@Entity
@DynamicUpdate
@NamedEntityGraph(
    name = "book.list", attributeNodes = [
        NamedAttributeNode("tags"),
        NamedAttributeNode("chapters"),
    ]
)
class Book(
    @Id
    var bookId: String,
    @Column(nullable = false)
    var name: String,
    var author: String?,
    @Column(nullable = false)
    var description: String,
    var source: String?,
    @ElementCollection(fetch = FetchType.EAGER)
    var tags: MutableSet<String> = mutableSetOf(),
    @OneToMany(cascade = [CascadeType.ALL], fetch = FetchType.LAZY, mappedBy = "book")
    var chapters: MutableSet<Chapter> = mutableSetOf(),
)

@Repository
interface BookRepository : JpaRepository<Book, String>, JpaSpecificationExecutor<Book> {
    @EntityGraph("book.list")
    override fun findAll(): List<Book>

    @Query("select distinct book.tags from Book book")
    fun findAllTag(): List<String>
}

@Entity
@DynamicUpdate
@NamedEntityGraph(
    name = "chapter.list", attributeNodes = [
        NamedAttributeNode("content"),
    ]
)
class Chapter(
    @Id
    var chapterId: String,
    @Column(nullable = false)
    var sequence: Int,
    var name: String?,
    var description: String?,
    @ManyToOne(cascade = [CascadeType.DETACH], fetch = FetchType.LAZY)
    @JoinColumn(nullable = false, foreignKey = ForeignKey(ConstraintMode.NO_CONSTRAINT))
    var book: Book,
    @OneToMany(cascade = [CascadeType.ALL], fetch = FetchType.LAZY, mappedBy = "chapter")
    var content: MutableSet<Line> = mutableSetOf(),
)

@Repository
interface ChapterRepository : JpaRepository<Chapter, String>, JpaSpecificationExecutor<Chapter>

@Entity
@DynamicUpdate
class Line(
    @Id
    var lineId: String,
    @Column(nullable = false)
    var sequence: Long,
    @Lob
    @Column(nullable = false)
    var text: String,
    @ManyToOne(cascade = [CascadeType.DETACH], fetch = FetchType.LAZY)
    @JoinColumn(nullable = false, foreignKey = ForeignKey(ConstraintMode.NO_CONSTRAINT))
    var chapter: Chapter
)

@Repository
interface LineRepository : JpaRepository<Line, String>, JpaSpecificationExecutor<Line>
