function Copy-GH3ToAddon {
    [CmdletBinding(SupportsShouldProcess = $true)]
    param(
        [string]$AddOnsPath = 'C:\Program Files (x86)\World of Warcraft\_retail_\Interface\AddOns',
        [string]$SourcePath = $(if ($script:GH3CopyScriptRoot) { $script:GH3CopyScriptRoot } else { (Get-Location).Path }),
        [switch]$NoMirror
    )

    if ([string]::IsNullOrWhiteSpace($SourcePath)) {
        throw 'SourcePath cannot be empty.'
    }

    $resolvedSource = (Resolve-Path -LiteralPath $SourcePath -ErrorAction Stop).Path
    $sourceForLeaf = $resolvedSource.TrimEnd([System.IO.Path]::DirectorySeparatorChar, [System.IO.Path]::AltDirectorySeparatorChar)
    $tocPath = Join-Path -Path $sourceForLeaf -ChildPath 'GH3.toc'

    if (-not (Test-Path -LiteralPath $tocPath -PathType Leaf)) {
        throw "GH3.toc not found in source folder: $sourceForLeaf"
    }

    if (-not (Test-Path -LiteralPath $AddOnsPath -PathType Container)) {
        throw "AddOns folder not found: $AddOnsPath"
    }

    $addonFolderName = Split-Path -Leaf $sourceForLeaf
    $destinationPath = Join-Path -Path $AddOnsPath -ChildPath $addonFolderName
    $excludedDirectories = @('.git', '.vscode', '.tmp-keymaster')
    $excludedRootDirectoriesToClean = @('.git', '.vscode', '.tmp-keymaster')
    $excludedExactFiles = @(
        '.curseignore',
        'Copy-GH3ToAddon.ps1',
        'DESCRIPTION.md',
        'GUILDHELPER_V3_PLAN.md',
        'newFeatures.MD'
    )
    $excludedFilePatterns = @(
        '*.md',
        '*.MD'
    )
    $excludedFiles = $excludedExactFiles + $excludedFilePatterns

    function Test-ExcludedFileName {
        param([string]$Name)

        if ($Name -in $excludedExactFiles) {
            return $true
        }

        foreach ($pattern in $excludedFilePatterns) {
            if ($Name -like $pattern) {
                return $true
            }
        }

        return $false
    }

    function Test-ExcludedRelativePath {
        param([string]$RelativePath)

        if ([string]::IsNullOrWhiteSpace($RelativePath)) {
            return $false
        }

        $normalizedRelativePath = $RelativePath -replace '[\\/]+', [System.IO.Path]::DirectorySeparatorChar
        $pathSegments = $normalizedRelativePath.Split([System.IO.Path]::DirectorySeparatorChar, [System.StringSplitOptions]::RemoveEmptyEntries)

        foreach ($segment in $pathSegments) {
            if ($segment -in $excludedDirectories) {
                return $true
            }
        }

        return Test-ExcludedFileName -Name ([System.IO.Path]::GetFileName($normalizedRelativePath))
    }

    function Sync-IncludedFiles {
        param(
            [string]$FromRoot,
            [string]$ToRoot
        )

        Get-ChildItem -LiteralPath $FromRoot -Recurse -File -Force |
            Where-Object {
                $relativePath = $_.FullName.Substring($FromRoot.Length).TrimStart([System.IO.Path]::DirectorySeparatorChar, [System.IO.Path]::AltDirectorySeparatorChar)
                -not (Test-ExcludedRelativePath -RelativePath $relativePath)
            } |
            ForEach-Object {
                $relativePath = $_.FullName.Substring($FromRoot.Length).TrimStart([System.IO.Path]::DirectorySeparatorChar, [System.IO.Path]::AltDirectorySeparatorChar)
                $destinationFile = Join-Path -Path $ToRoot -ChildPath $relativePath
                $destinationDirectory = Split-Path -Parent $destinationFile

                if (-not (Test-Path -LiteralPath $destinationDirectory -PathType Container)) {
                    New-Item -ItemType Directory -Path $destinationDirectory -Force | Out-Null
                }

                Copy-Item -LiteralPath $_.FullName -Destination $destinationFile -Force
            }
    }

    if (-not (Test-Path -LiteralPath $destinationPath -PathType Container)) {
        if ($PSCmdlet.ShouldProcess($destinationPath, 'Create addon destination folder')) {
            New-Item -ItemType Directory -Path $destinationPath -Force | Out-Null
        }
    }

    if ($NoMirror) {
        if ($PSCmdlet.ShouldProcess($destinationPath, "Copy GH3 files from $sourceForLeaf")) {
            Get-ChildItem -LiteralPath $sourceForLeaf -Force |
                Where-Object {
                    if ($_.PSIsContainer) {
                        $_.Name -notin $excludedDirectories
                    }
                    else {
                        -not (Test-ExcludedFileName -Name $_.Name)
                    }
                } |
                Copy-Item -Destination $destinationPath -Recurse -Force

            Sync-IncludedFiles -FromRoot $sourceForLeaf -ToRoot $destinationPath
        }
    }
    else {
        $robocopyArgs = @(
            $sourceForLeaf
            $destinationPath
            '/MIR'
            '/R:1'
            '/W:1'
            '/NFL'
            '/NDL'
            '/NJH'
            '/NJS'
            '/NP'
            '/XD'
        ) + $excludedDirectories + @('/XF') + $excludedFiles

        if ($PSCmdlet.ShouldProcess($destinationPath, "Mirror GH3 files from $sourceForLeaf")) {
            & robocopy @robocopyArgs | Out-Null

            if ($LASTEXITCODE -ge 8) {
                throw "Robocopy failed with exit code $LASTEXITCODE"
            }

            Sync-IncludedFiles -FromRoot $sourceForLeaf -ToRoot $destinationPath
        }
    }

    if ($PSCmdlet.ShouldProcess($destinationPath, 'Remove stale development-only files')) {
        foreach ($directoryName in $excludedRootDirectoriesToClean) {
            $staleDirectory = Join-Path -Path $destinationPath -ChildPath $directoryName

            if (Test-Path -LiteralPath $staleDirectory) {
                Remove-Item -LiteralPath $staleDirectory -Recurse -Force
            }
        }

        Get-ChildItem -LiteralPath $destinationPath -File -Force |
            Where-Object {
                Test-ExcludedFileName -Name $_.Name
            } |
            Remove-Item -Force
    }

    if ($WhatIfPreference) {
        Write-Host "Would copy $addonFolderName to $destinationPath"
    }
    else {
        Write-Host "Copied $addonFolderName to $destinationPath"
    }

    return $destinationPath
}

if ($PSScriptRoot) {
    $script:GH3CopyScriptRoot = $PSScriptRoot
}
elseif ($PSCommandPath) {
    $script:GH3CopyScriptRoot = Split-Path -Parent $PSCommandPath
}
elseif ($MyInvocation.MyCommand.Path) {
    $script:GH3CopyScriptRoot = Split-Path -Parent $MyInvocation.MyCommand.Path
}
else {
    $script:GH3CopyScriptRoot = (Get-Location).Path
}

# Examples:
# . .\Copy-GH3ToAddon.ps1
Copy-GH3ToAddon -AddOnsPath 'C:\Program Files (x86)\World of Warcraft\_retail_\Interface\AddOns'
# Copy-GH3ToAddon -AddOnsPath 'C:\Program Files (x86)\World of Warcraft\_retail_\Interface\AddOns' -WhatIf
# Copy-GH3ToAddon -NoMirror