package ch.dissem.yaep.domain

import ch.tutteli.atrium.api.fluent.en_GB.notToEqualNull
import ch.tutteli.atrium.api.fluent.en_GB.toEqual
import ch.tutteli.atrium.api.verbs.expect
import kotlin.test.Test

class NeighbourClueTest : ClueTest() {

    @Test
    fun `ensure actual neighbours are valid`() {
        val grid = createGrid()
        for (ia in 0 until size) {
            for (ib in 0 until size) {
                for (j in 1 until size) {
                    val a = grid[ia][j - 1]
                    val b = grid[ib][j]

                    expect(a.solution).notToEqualNull()
                    expect(b.solution).notToEqualNull()
                    a.solution!!
                    b.solution!!

                    expect(NeighbourClue(a.solution, b.solution).isValid(grid)).toEqual(true)
                    expect(NeighbourClue(b.solution, a.solution).isValid(grid)).toEqual(true)
                }
            }
        }
    }

    @Test
    fun `ensure non-neighbours are invalid`() {
        val grid = createGrid()
        for (ia in 0 until size) {
            for (ib in 0 until size) {
                for (ja in 0 until size) {
                    for (jb in 0 until size) {
                        if (ja == jb + 1 || ja == jb - 1) {
                            continue
                        }
                        val a = grid[ia][ja]
                        val b = grid[ib][jb]

                        expect(a.solution).notToEqualNull()
                        expect(b.solution).notToEqualNull()
                        a.solution!!
                        b.solution!!

                        expect(NeighbourClue(a.solution, b.solution).isValid(grid)).toEqual(false)
                        expect(NeighbourClue(b.solution, a.solution).isValid(grid)).toEqual(false)
                    }
                }
            }
        }
    }

    @Test
    fun `ensure grid with one neighbour not set is considered valid if a neighbour is in the options`() {
        val grid = createGrid()
        for (ia in 0 until size) {
            for (ib in 0 until size) {
                for (j in 1 until size) {
                    val rowA = grid[ia]
                    val rowB = grid[ib]
                    val a = rowA[j - 1]
                    val b = rowB[j]

                    expect(a.solution).notToEqualNull()
                    expect(b.solution).notToEqualNull()
                    a.solution!!
                    b.solution!!

                    rowA.forEach { it.selection = null; it.options.clear() }
                    rowB.forEach { it.selection = null; it.options.clear() }

                    a.selection = null
                    a.options.add(a.solution)
                    b.selection = b.solution
                    b.options.clear()

                    expect(NeighbourClue(a.solution, b.solution).isValid(grid)).toEqual(true)
                    expect(NeighbourClue(b.solution, a.solution).isValid(grid)).toEqual(true)

                    a.selection = a.solution
                    a.options.clear()
                    b.selection = null
                    b.options.add(b.solution)

                    expect(NeighbourClue(a.solution, b.solution).isValid(grid)).toEqual(true)
                    expect(NeighbourClue(b.solution, a.solution).isValid(grid)).toEqual(true)

                    if (j < size - 1) {
                        val notA = rowA[j + 1]

                        a.selection = null
                        a.options.clear()
                        notA.options.add(a.solution)
                        b.selection = b.solution
                        b.options.clear()

                        expect(NeighbourClue(a.solution, b.solution).isValid(grid)).toEqual(true)
                        expect(NeighbourClue(b.solution, a.solution).isValid(grid)).toEqual(true)
                    }
                }
            }
        }
    }

    @Test
    fun `ensure grid with a and c more than one cell between is not considered valid`() {
        val grid = createGrid { null }
        val rowA = grid.random()
        val rowB = grid.random()
        val a = rowA[1]
        val b = rowB[2]

        expect(a.solution).notToEqualNull()
        expect(b.solution).notToEqualNull()
        a.solution!!
        b.solution!!

        a.selection = a.solution

        rowB[3].selection = b.solution

        expect(NeighbourClue(a.solution, b.solution).isValid(grid)).toEqual(false)
        expect(NeighbourClue(b.solution, a.solution).isValid(grid)).toEqual(false)
    }

}
