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

package space.rcmd.android.sizzle.model

/**
 * The whole song in memory. This single object is what gets saved to / loaded
 * from the `.sng` file format and what the audio engine reads while playing.
 * Keeping one root object makes serialization and undo/redo straightforward.
 *
 * Persistence is done by our own text serializer (see
 * [space.rcmd.android.sizzle.io.ProjectIo]), not kotlinx, so the
 * model classes carry no serialization annotations.
 */
class Project {
    var name: String = "untitled"

    // ----- Global transport -----
    var tempoBpm: Float = 120f
    var timeSignature: TimeSignature = TimeSignature.FOUR_FOUR
    var scale: Scale = Scale.CHROMATIC
    /** Root note as a pitch-class 0..11 (0 = C). Used with [scale] for entry. */
    var rootNote: Int = 0

    // ----- Content -----
    /**
     * One pattern/block per arrangement lane. Lane i is tied to block i (the
     * "sizzletracker CLI" model): enabling a cell on arrangement lane i schedules
     * block i to play when the playhead reaches that beat. Block id == lane index.
     */
    val patterns: MutableList<Pattern> = MutableList(Arrangement.LANE_COUNT) {
        // Default to the shortest length for the signature: 16 ticks for 4/4.
        Pattern(id = it, name = "BLK${it + 1}", length = timeSignature.lengthOptions[0])
    }
    val arrangement: Arrangement = Arrangement()
    val mixer: Mixer = Mixer()
    /** 16 toolbox slots (tab 3). Index in the list == on-screen slot number. */
    val toolbox: MutableList<ToolboxSlot> = MutableList(TOOLBOX_SLOTS) { ToolboxSlot(it) }

    /** Look up a pattern by id. Indexed loop (not `firstOrNull`) so it allocates no
     *  Iterator — this is called once per output sample on the audio thread. */
    fun pattern(id: Int): Pattern? {
        for (i in patterns.indices) {
            val p = patterns[i]
            if (p.id == id) return p
        }
        return null
    }

    /** Which pattern the tracker tab is currently editing. */
    var activePatternId: Int = 0

    fun activePattern(): Pattern = pattern(activePatternId) ?: patterns.first()

    companion object {
        const val TOOLBOX_SLOTS = 16
    }
}
