package net.sergeych.toread.fb2

import java.io.File
import java.util.Base64
import kotlin.test.Test
import kotlin.test.assertContentEquals
import kotlin.test.assertEquals
import kotlin.test.assertNotNull
import kotlin.test.assertTrue

class Fb2FixtureBookTest {
    @Test
    fun parsesOnlyBookFromTestBooksWithImagesInPlace() {
        val bookFile = findTestBooksDirectory()
            .listFiles { file -> file.isFile && file.name.endsWith(".fb2.zip") }
            .orEmpty()
            .single()

        val book = Fb2Format.parse(bookFile.readBytes(), bookFile.name)

        assertEquals("Записки Терезы Нумы", book.title)
        assertEquals(listOf("prose_contemporary"), book.genres)
        assertEquals("ru", book.language)
        assertEquals("it", book.sourceLanguage)
        assertEquals("1976", book.date)
        assertEquals("Дача Мараини", book.authors.single().displayName)
        assertEquals("Николай Борисович Томашевский", book.translators.single().displayName)
        assertTrue(book.annotation.orEmpty().startsWith("«Записки Терезы Нумы»"))

        assertEquals("F99D3F1D-2A6C-4349-B7CF-1A390A38745A", book.documentInfo.id)
        assertEquals("1.0", book.documentInfo.version)
        assertEquals("12 May 2026", book.documentInfo.date)
        assertEquals("alexej36", book.documentInfo.authors.single().displayName)

        assertEquals(listOf("Дача Мараини", "ЗАПИСКИ ТЕРЕЗЫ НУМЫ", "Роман"), book.bodyTitle)
        assertEquals(listOf("#i_001.png"), book.bodyImages.map { it.href })
        assertEquals(2, book.sections.size)
        assertEquals("ПРЕДИСЛОВИЕ", book.sections[0].title)
        assertTrue(book.sections[0].paragraphs.first().startsWith("Роман Дачи Мараини"))
        assertEquals(emptyList(), book.sections[0].images)
        assertEquals("ЗАПИСКИ ТЕРЕЗЫ НУМЫ", book.sections[1].title)
        assertEquals(listOf("#i_002.png", "#i_003.png", "#i_004.jpg"), book.sections[1].images.map { it.href })
        assertTrue(book.sections[1].paragraphs.size > 4_000)

        assertEquals(listOf("#cover.jpg"), book.coverImages.map { it.href })
        assertEquals(
            listOf("cover.jpg", "i_001.png", "i_002.png", "i_003.png", "i_004.jpg"),
            book.binaries.map { it.id },
        )

        assertImageBinary(book, book.coverImages.single(), "image/jpeg", jpegSignature)
        assertImageBinary(book, book.bodyImages.single(), "image/png", pngSignature)
        book.sections[1].images.forEach { image ->
            val expectedSignature = if (image.href.endsWith(".jpg")) jpegSignature else pngSignature
            val expectedContentType = if (image.href.endsWith(".jpg")) "image/jpeg" else "image/png"
            assertImageBinary(book, image, expectedContentType, expectedSignature)
        }
    }

    private fun findTestBooksDirectory(): File {
        var current = File(System.getProperty("user.dir")).absoluteFile
        while (true) {
            val candidate = File(current, "test_books")
            if (candidate.isDirectory) return candidate
            current = current.parentFile ?: error("Could not find test_books directory")
        }
    }

    private fun assertImageBinary(
        book: Fb2Book,
        image: Fb2ImageRef,
        contentType: String,
        signature: ByteArray,
    ) {
        val binary = assertNotNull(book.binaryFor(image), "Missing binary for ${image.href}")
        assertEquals(image.binaryId, binary.id)
        assertEquals(contentType, binary.contentType)
        val bytes = Base64.getDecoder().decode(binary.base64)
        assertContentEquals(signature, bytes.copyOf(signature.size))
    }

    private val pngSignature = byteArrayOf(
        0x89.toByte(),
        0x50,
        0x4e,
        0x47,
        0x0d,
        0x0a,
        0x1a,
        0x0a,
    )

    private val jpegSignature = byteArrayOf(
        0xff.toByte(),
        0xd8.toByte(),
        0xff.toByte(),
    )
}
