package terminal

import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test

import testutil.LispTestInstance

@LispTestInstance
class TerminalHistoryTest {

    private lateinit var history: TerminalHistory

    private fun assertAtBeginning() {
        assertThat(history.isBeginning()).isTrue()
    }

    private fun assertAtEnd() {
        assertThat(history.isEnd()).isTrue()
    }

    private fun assertPrevious(expected: String) {
        assertThat(history.getPreviousLine()).isEqualTo(expected)
    }

    private fun assertNext(expected: String) {
        assertThat(history.getNextLine()).isEqualTo(expected)
    }

    @BeforeEach
    fun setUp() {
        history = TerminalHistory()
    }

    @Test
    fun `history starts with no lines`() {
        assertAtBeginning()
        assertAtEnd()
    }

    @Test
    fun `add one line to the history`() {
        history.addLine("test line")

        assertPrevious("test line")
        assertAtBeginning()
    }

    @Test
    fun `current line is empty`() {
        history.addLine("one")
        history.getPreviousLine()

        assertNext("")
    }

    @Test
    fun `move backwards`() {
        history.addLine("one")
        history.addLine("two")

        assertPrevious("two")
        assertPrevious("one")
        assertAtBeginning()
    }

    @Test
    fun `move forwards`() {
        history.addLine("one")
        history.addLine("two")
        history.getPreviousLine()
        history.getPreviousLine()

        assertNext("two")
        assertNext("")
        assertAtEnd()
    }

    @Test
    fun `added line goes to the end of the history`() {
        history.addLine("one")
        history.addLine("two")
        history.getPreviousLine()
        history.getPreviousLine()
        history.addLine("three")

        assertPrevious("three")
        assertPrevious("two")
        assertPrevious("one")
        assertAtBeginning()
    }

    @Test
    fun `current line is updated`() {
        history.addLine("one")
        history.updateCurrentLine("purple")
        history.getPreviousLine()

        assertNext("purple")
    }

    @Test
    fun `previous line is updated`() {
        history.addLine("one")
        history.addLine("two")
        history.getPreviousLine()
        history.updateCurrentLine("purple")
        history.getPreviousLine()

        assertNext("purple")
    }

    @Test
    fun `going past the first line keeps returning the first line`() {
        history.addLine("one")
        history.addLine("two")
        history.getPreviousLine()
        history.getPreviousLine()
        history.getPreviousLine()
        history.getPreviousLine()
        history.getPreviousLine()

        assertPrevious("one")
    }

    @Test
    fun `going past the last line keeps returning the last line`() {
        history.updateCurrentLine("current")
        history.getNextLine()
        history.getNextLine()
        history.getNextLine()
        history.getNextLine()

        assertNext("current")
    }
}