// SPDX-FileCopyrightText: 2026 Reactorcoremeltdown
// SPDX-License-Identifier: GPL-3.0-or-later

package space.rcmd.android.sizzle.io

import space.rcmd.android.sizzle.model.Arrangement
import space.rcmd.android.sizzle.model.Pitch
import space.rcmd.android.sizzle.model.Project
import space.rcmd.android.sizzle.model.TimeSignature
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotEquals
import org.junit.Assert.assertTrue
import org.junit.Test

/** Verifies the `.sng` reader/writer against the reference desktop format. */
class SngFormatTest {

    private val reference = """
        version 1
        bpm 120
        sig 4 4

        block A 16 4
        roll ####
        track T1 0
        0 C-4 64 01
        4 E-4 .. ..
        8 OFF .. ..
        endblock
    """.trimIndent()

    @Test
    fun parsesReferenceExample() {
        val p = SngFormat.importInto(Project(), reference)

        assertEquals(120f, p.tempoBpm, 0.001f)
        assertEquals(TimeSignature.FOUR_FOUR, p.timeSignature)

        val block = p.patterns[0]
        assertEquals("A", block.name)
        assertEquals(16, block.length)

        val c0 = block.cell(0, 0)
        assertEquals(Pitch.parse("C-4"), c0.note)
        assertEquals(0x64, c0.velocity)   // velocity is hexadecimal
        assertEquals(1, c0.channel)

        val c4 = block.cell(0, 4)
        assertEquals(Pitch.parse("E-4"), c4.note)
        assertEquals(0x7F, c4.velocity)   // ".." -> default (full MIDI velocity)
        assertEquals(1, c4.channel)       // ".." -> inherit track channel (0 -> 1)

        assertTrue(block.cell(0, 8).isNoteOff)

        // roll "####" enables block 0 on beats 0..3 of its own lane.
        for (beat in 0..3) assertNotEquals(Arrangement.EMPTY, p.arrangement.patternAt(0, beat))
        assertEquals(Arrangement.EMPTY, p.arrangement.patternAt(0, 4))
    }

    @Test
    fun roundTripsNotesAndRoll() {
        val p = Project()
        p.tempoBpm = 140f
        p.timeSignature = TimeSignature.FIVE_FOUR
        p.patterns[0].cell(0, 0).apply { note = 60; velocity = 0x40; channel = 3 }
        p.patterns[0].cell(1, 5).apply { note = 67; velocity = 0x7F; channel = 2 }
        p.arrangement.set(0, 0, 0)
        p.arrangement.set(0, 1, 0)

        val restored = SngFormat.importInto(Project(), SngFormat.export(p))

        assertEquals(140f, restored.tempoBpm, 0.001f)
        assertEquals(TimeSignature.FIVE_FOUR, restored.timeSignature)
        restored.patterns[0].cell(0, 0).let {
            assertEquals(60, it.note); assertEquals(0x40, it.velocity); assertEquals(3, it.channel)
        }
        restored.patterns[0].cell(1, 5).let {
            assertEquals(67, it.note); assertEquals(0x7F, it.velocity); assertEquals(2, it.channel)
        }
        assertNotEquals(Arrangement.EMPTY, restored.arrangement.patternAt(0, 0))
        assertNotEquals(Arrangement.EMPTY, restored.arrangement.patternAt(0, 1))
    }
}
