BeforeAll {
    Import-Module (Join-Path $PSScriptRoot '..' 'AgentAssets.psm1') -Force

    function New-TempTree {
        $root = Join-Path ([System.IO.Path]::GetTempPath()) ("agentassets_" + [guid]::NewGuid().ToString('N'))
        $source = Join-Path $root 'plugin/skills/demo'
        New-Item -ItemType Directory -Path $source -Force | Out-Null
        Set-Content -LiteralPath (Join-Path $source 'SKILL.md') -Value 'demo' -Encoding utf8
        return [pscustomobject]@{ Root = $root; Source = $source; Link = (Join-Path $root '.claude/skills/demo') }
    }
}

Describe 'Sync-AgentSkillLink' {
    It 'создаёт junction на исходный навык' {
        $t = New-TempTree
        try {
            Sync-AgentSkillLink -SourcePath $t.Source -LinkPath $t.Link | Should -Be 'Created'
            (Get-Item -LiteralPath $t.Link -Force).LinkType | Should -Be 'Junction'
            Get-Content -LiteralPath (Join-Path $t.Link 'SKILL.md') | Should -Be 'demo'
        } finally { Remove-Item -LiteralPath $t.Root -Recurse -Force -ErrorAction SilentlyContinue }
    }

    It 'идемпотентен: повторный запуск ничего не ломает' {
        $t = New-TempTree
        try {
            Sync-AgentSkillLink -SourcePath $t.Source -LinkPath $t.Link | Out-Null
            Sync-AgentSkillLink -SourcePath $t.Source -LinkPath $t.Link | Should -Be 'AlreadyLinked'
        } finally { Remove-Item -LiteralPath $t.Root -Recurse -Force -ErrorAction SilentlyContinue }
    }

    It 'не трогает настоящий каталог, а падает с понятной ошибкой' {
        $t = New-TempTree
        try {
            New-Item -ItemType Directory -Path $t.Link -Force | Out-Null
            Set-Content -LiteralPath (Join-Path $t.Link 'mine.md') -Value 'ручное' -Encoding utf8

            { Sync-AgentSkillLink -SourcePath $t.Source -LinkPath $t.Link } | Should -Throw '*не является junction*'
            Get-Content -LiteralPath (Join-Path $t.Link 'mine.md') | Should -Be 'ручное'
        } finally { Remove-Item -LiteralPath $t.Root -Recurse -Force -ErrorAction SilentlyContinue }
    }

    It 'Test-AgentSkillLink различает связанное и несвязанное состояние' {
        $t = New-TempTree
        try {
            Test-AgentSkillLink -SourcePath $t.Source -LinkPath $t.Link | Should -BeFalse
            Sync-AgentSkillLink -SourcePath $t.Source -LinkPath $t.Link | Out-Null
            Test-AgentSkillLink -SourcePath $t.Source -LinkPath $t.Link | Should -BeTrue
        } finally { Remove-Item -LiteralPath $t.Root -Recurse -Force -ErrorAction SilentlyContinue }
    }

    It 'бросает понятную ошибку, если SourcePath не существует' {
        $t = New-TempTree
        try {
            $missing = Join-Path $t.Root 'plugin/skills/nope'
            { Sync-AgentSkillLink -SourcePath $missing -LinkPath $t.Link } | Should -Throw '*нет исходного навыка*'
        } finally { Remove-Item -LiteralPath $t.Root -Recurse -Force -ErrorAction SilentlyContinue }
    }

    It 'перелинковка: ссылка на другой источник не трогает файлы старого источника' {
        $t = New-TempTree
        try {
            $source2 = Join-Path $t.Root 'plugin/skills/demo2'
            New-Item -ItemType Directory -Path $source2 -Force | Out-Null
            Set-Content -LiteralPath (Join-Path $source2 'SKILL.md') -Value 'demo2' -Encoding utf8

            Sync-AgentSkillLink -SourcePath $t.Source -LinkPath $t.Link | Should -Be 'Created'
            Sync-AgentSkillLink -SourcePath $source2 -LinkPath $t.Link | Should -Be 'Created'

            Get-Content -LiteralPath (Join-Path $t.Link 'SKILL.md') | Should -Be 'demo2'
            Get-Content -LiteralPath (Join-Path $t.Source 'SKILL.md') | Should -Be 'demo'
        } finally { Remove-Item -LiteralPath $t.Root -Recurse -Force -ErrorAction SilentlyContinue }
    }

    It 'AllowCopy: ошибка Copy-Item не должна проглатываться независимо от ErrorActionPreference вызывающего' {
        # Явно 'Continue' — воспроизводим вызывающего БЕЗ $ErrorActionPreference='Stop'
        # (run-ps-tests.ps1 сам выставляет 'Stop' на уровне скрипта, и это маскировало бы баг).
        $ErrorActionPreference = 'Continue'
        $t = New-TempTree
        # Родительский каталог создаём заранее — иначе Mock New-Item с -ParameterFilter
        # по Junction перехватит и вызов New-Item -ItemType Directory (родитель LinkPath)
        # и провалится с "No mock matched", маскируя настоящий баг Copy-Item.
        New-Item -ItemType Directory -Path (Split-Path -Parent $t.Link) -Force | Out-Null
        try {
            Mock -ModuleName AgentAssets New-Item -ParameterFilter { $ItemType -eq 'Junction' } { throw 'junction недоступен (симуляция)' }
            # [CmdletBinding()] обязателен: только у advanced-функции переданный вызывающим
            # -ErrorAction реально локализует $ErrorActionPreference внутри тела мока —
            # иначе мок не воспроизводит поведение настоящего Copy-Item.
            Mock -ModuleName AgentAssets Copy-Item {
                [CmdletBinding()]
                param($LiteralPath, $Destination, [switch]$Recurse, [switch]$Force)
                Write-Error 'copy failed (симуляция)'
            }

            { Sync-AgentSkillLink -SourcePath $t.Source -LinkPath $t.Link -AllowCopy } | Should -Throw
        } finally { Remove-Item -LiteralPath $t.Root -Recurse -Force -ErrorAction SilentlyContinue }
    }
}

Describe 'Remove-AgentSkillLink' {
    It 'снимает junction, оставляя исходный навык нетронутым' {
        $t = New-TempTree
        try {
            Sync-AgentSkillLink -SourcePath $t.Source -LinkPath $t.Link | Out-Null

            Remove-AgentSkillLink -LinkPath $t.Link | Should -Be 'Removed'
            Test-Path -LiteralPath $t.Link | Should -BeFalse
            Get-Content -LiteralPath (Join-Path $t.Source 'SKILL.md') | Should -Be 'demo'
        } finally { Remove-Item -LiteralPath $t.Root -Recurse -Force -ErrorAction SilentlyContinue }
    }

    It 'снимает junction с исчезнувшим источником (ветка без plugin/skills)' {
        $t = New-TempTree
        try {
            Sync-AgentSkillLink -SourcePath $t.Source -LinkPath $t.Link | Out-Null
            Remove-Item -LiteralPath $t.Source -Recurse -Force

            Remove-AgentSkillLink -LinkPath $t.Link | Should -Be 'Removed'
            Test-Path -LiteralPath $t.Link | Should -BeFalse
        } finally { Remove-Item -LiteralPath $t.Root -Recurse -Force -ErrorAction SilentlyContinue }
    }

    It 'не трогает настоящий каталог' {
        $t = New-TempTree
        try {
            New-Item -ItemType Directory -Path $t.Link -Force | Out-Null
            Set-Content -LiteralPath (Join-Path $t.Link 'mine.md') -Value 'ручное' -Encoding utf8

            Remove-AgentSkillLink -LinkPath $t.Link | Should -Be 'Skipped'
            Get-Content -LiteralPath (Join-Path $t.Link 'mine.md') | Should -Be 'ручное'
        } finally { Remove-Item -LiteralPath $t.Root -Recurse -Force -ErrorAction SilentlyContinue }
    }

    It 'на отсутствующем пути сообщает Missing и не падает' {
        $t = New-TempTree
        try {
            Remove-AgentSkillLink -LinkPath $t.Link | Should -Be 'Missing'
        } finally { Remove-Item -LiteralPath $t.Root -Recurse -Force -ErrorAction SilentlyContinue }
    }

    It 'идемпотентен: повторное снятие даёт Missing' {
        $t = New-TempTree
        try {
            Sync-AgentSkillLink -SourcePath $t.Source -LinkPath $t.Link | Out-Null

            Remove-AgentSkillLink -LinkPath $t.Link | Should -Be 'Removed'
            Remove-AgentSkillLink -LinkPath $t.Link | Should -Be 'Missing'
        } finally { Remove-Item -LiteralPath $t.Root -Recurse -Force -ErrorAction SilentlyContinue }
    }
}
