Tests/New-ElmTextarea.Tests.ps1

BeforeAll {
    . $PSScriptRoot/../Public/View/New-ElmTextarea.ps1
}

Describe 'New-ElmTextarea' -Tag 'Unit', 'P10' {

    Context 'Return value structure' {
        It 'Should return a Box node' {
            $ta = New-ElmTextarea -Lines @('hello')
            $ta.Type | Should -Be 'Box'
        }

        It 'Should have Direction Vertical' {
            $ta = New-ElmTextarea -Lines @('hello')
            $ta.Direction | Should -Be 'Vertical'
        }

        It 'Should have Width Auto' {
            $ta = New-ElmTextarea -Lines @('hello')
            $ta.Width | Should -Be 'Auto'
        }

        It 'Should have Height Auto' {
            $ta = New-ElmTextarea -Lines @('hello')
            $ta.Height | Should -Be 'Auto'
        }

        It 'Should have a Children array' {
            $ta = New-ElmTextarea -Lines @('hello')
            $ta.Children | Should -Not -BeNull
        }
    }

    Context 'Placeholder rendering' {
        It 'Should show placeholder as single Text child when Lines is empty string and not focused' {
            $ta = New-ElmTextarea -Lines @('') -Placeholder 'Type here...'
            $ta.Children[0].Content | Should -Be 'Type here...'
        }

        It 'Should NOT show placeholder when focused' {
            $ta = New-ElmTextarea -Lines @('') -Placeholder 'hint' -Focused
            $ta.Children[0].Content | Should -Be '|'
        }

        It 'Should NOT show placeholder when Lines has content' {
            $ta = New-ElmTextarea -Lines @('hello') -Placeholder 'hint'
            $ta.Children[0].Content | Should -Be 'hello'
        }

        It 'Should NOT show placeholder when Placeholder is empty string' {
            $ta = New-ElmTextarea -Lines @('')
            $ta.Children[0].Content | Should -Be ''
        }
    }

    Context 'Unfocused rendering' {
        It 'Should render each line as a separate Text child' {
            $ta = New-ElmTextarea -Lines @('line1', 'line2', 'line3')
            $ta.Children.Count | Should -Be 3
        }

        It 'Should render line content exactly' {
            $ta = New-ElmTextarea -Lines @('hello', 'world')
            $ta.Children[0].Content | Should -Be 'hello'
            $ta.Children[1].Content | Should -Be 'world'
        }

        It 'Should render empty line as empty string child' {
            $ta = New-ElmTextarea -Lines @('a', '', 'b')
            $ta.Children[1].Content | Should -Be ''
        }
    }

    Context 'Focused cursor rendering' {
        It 'Should insert cursor at end when CursorCol equals line length' {
            $ta = New-ElmTextarea -Lines @('hello') -CursorRow 0 -CursorCol 5 -Focused
            $ta.Children[0].Content | Should -Be 'hello|'
        }

        It 'Should insert cursor at beginning when CursorCol is 0' {
            $ta = New-ElmTextarea -Lines @('hello') -CursorRow 0 -CursorCol 0 -Focused
            $ta.Children[0].Content | Should -Be '|hello'
        }

        It 'Should insert cursor in middle of line' {
            $ta = New-ElmTextarea -Lines @('hello') -CursorRow 0 -CursorCol 2 -Focused
            $ta.Children[0].Content | Should -Be 'he|llo'
        }

        It 'Should only insert cursor on the CursorRow, not other lines' {
            $ta = New-ElmTextarea -Lines @('line1', 'line2', 'line3') -CursorRow 1 -CursorCol 2 -Focused
            $ta.Children[0].Content | Should -Be 'line1'
            $ta.Children[1].Content | Should -Be 'li|ne2'
            $ta.Children[2].Content | Should -Be 'line3'
        }

        It 'Should use custom CursorChar' {
            $ta = New-ElmTextarea -Lines @('hi') -CursorRow 0 -CursorCol 2 -Focused -CursorChar '_'
            $ta.Children[0].Content | Should -Be 'hi_'
        }
    }

    Context 'CursorRow and CursorCol clamping' {
        It 'Should clamp CursorRow below 0 to 0' {
            $ta = New-ElmTextarea -Lines @('a', 'b') -CursorRow -1 -CursorCol 0 -Focused
            $ta.Children[0].Content | Should -Be '|a'
        }

        It 'Should clamp CursorRow above last index to last index' {
            $ta = New-ElmTextarea -Lines @('a', 'b') -CursorRow 99 -CursorCol 0 -Focused
            $ta.Children[1].Content | Should -Be '|b'
        }

        It 'Should clamp CursorCol below 0 to 0' {
            $ta = New-ElmTextarea -Lines @('hello') -CursorRow 0 -CursorCol -5 -Focused
            $ta.Children[0].Content | Should -Be '|hello'
        }

        It 'Should clamp CursorCol above line length to line length' {
            $ta = New-ElmTextarea -Lines @('hi') -CursorRow 0 -CursorCol 99 -Focused
            $ta.Children[0].Content | Should -Be 'hi|'
        }
    }

    Context 'MaxVisible windowing' {
        It 'Should render only MaxVisible lines' {
            $lines = 1..10 | ForEach-Object { "Line $_" }
            $ta    = New-ElmTextarea -Lines $lines -MaxVisible 4
            $ta.Children.Count | Should -Be 4
        }

        It 'Should start window at ScrollOffset' {
            $ta = New-ElmTextarea -Lines @('A', 'B', 'C', 'D', 'E') -MaxVisible 3 -ScrollOffset 1
            $ta.Children[0].Content | Should -Be 'B'
        }

        It 'Should render all lines when count is within MaxVisible' {
            $ta = New-ElmTextarea -Lines @('X', 'Y') -MaxVisible 10
            $ta.Children.Count | Should -Be 2
        }
    }

    Context 'ScrollOffset clamping' {
        It 'Should clamp ScrollOffset below 0 to 0' {
            $ta = New-ElmTextarea -Lines @('A', 'B', 'C') -MaxVisible 2 -ScrollOffset -5
            $ta.Children[0].Content | Should -Be 'A'
        }

        It 'Should clamp ScrollOffset so window does not exceed line count' {
            $ta = New-ElmTextarea -Lines @('A', 'B', 'C') -MaxVisible 2 -ScrollOffset 99
            $ta.Children[0].Content | Should -Be 'B'
        }
    }

    Context 'Style passthrough' {
        It 'Should apply Style to lines when not focused' {
            $s  = [PSCustomObject]@{ Foreground = 'White' }
            $ta = New-ElmTextarea -Lines @('hello') -Style $s
            $ta.Children[0].Style | Should -Be $s
        }

        It 'Should apply FocusedStyle to lines when focused and FocusedStyle is set' {
            $fs = [PSCustomObject]@{ Foreground = 'BrightWhite' }
            $ta = New-ElmTextarea -Lines @('hello') -CursorRow 0 -CursorCol 0 -Focused -FocusedStyle $fs
            $ta.Children[0].Style | Should -Be $fs
        }

        It 'Should fall back to Style when Focused but FocusedStyle is null' {
            $s  = [PSCustomObject]@{ Foreground = 'White' }
            $ta = New-ElmTextarea -Lines @('hello') -CursorRow 0 -CursorCol 0 -Focused -Style $s
            $ta.Children[0].Style | Should -Be $s
        }
    }

    Context 'FocusedBoxStyle — outer Box style when focused' {
        It 'Should apply FocusedBoxStyle to the outer Box when focused' {
            $fbs = [PSCustomObject]@{ Border = 'Rounded' }
            $ta  = New-ElmTextarea -Lines @('hello') -CursorRow 0 -CursorCol 0 -Focused -FocusedBoxStyle $fbs
            $ta.Style | Should -Be $fbs
        }

        It 'Should still return a Box/Vertical node when FocusedBoxStyle is provided' {
            $fbs = [PSCustomObject]@{ Border = 'Rounded' }
            $ta  = New-ElmTextarea -Lines @('hello') -CursorRow 0 -CursorCol 0 -Focused -FocusedBoxStyle $fbs
            $ta.Type      | Should -Be 'Box'
            $ta.Direction | Should -Be 'Vertical'
        }

        It 'Should still render text children when FocusedBoxStyle is provided' {
            $fbs = [PSCustomObject]@{ Border = 'Rounded' }
            $ta  = New-ElmTextarea -Lines @('hello') -CursorRow 0 -CursorCol 5 -Focused -FocusedBoxStyle $fbs
            $ta.Children[0].Content | Should -Be 'hello|'
        }

        It 'Should have null outer Box Style when focused but FocusedBoxStyle is null' {
            $ta = New-ElmTextarea -Lines @('hello') -CursorRow 0 -CursorCol 0 -Focused
            $ta.Style | Should -BeNullOrEmpty
        }

        It 'Should have null outer Box Style when unfocused even if FocusedBoxStyle is provided' {
            $fbs = [PSCustomObject]@{ Border = 'Rounded' }
            $ta  = New-ElmTextarea -Lines @('hello') -FocusedBoxStyle $fbs
            $ta.Style | Should -BeNullOrEmpty
        }

        It 'Should keep FocusedStyle on text children independently of FocusedBoxStyle' {
            $fbs = [PSCustomObject]@{ Border = 'Rounded' }
            $fs  = [PSCustomObject]@{ Foreground = 'BrightWhite' }
            $ta  = New-ElmTextarea -Lines @('hello') -CursorRow 0 -CursorCol 0 -Focused -FocusedBoxStyle $fbs -FocusedStyle $fs
            $ta.Children[0].Style | Should -Be $fs
        }
    }
}