param (
    [string]$repofile,
    [string]$repolist,
    [string]$action,
    [string]$token,
    [string]$owner,
    [string]$outputfile,
    [string]$collaborator,
    [string]$collab_permission,
    [switch]$help,
    [int]$maxrepos = 1000
)

function Show-Help {
    @"
This script allows you to pass a GitHub CLI command as an argument and a list of repositories or a file containing repository names to execute the 'gh' CLI command in batch.

Supported Actions:
- gh repo edit --visibility private: Edit the visibility of repositories.
- gh repo delete: Delete repositories.
- add-collaborator: Add a collaborator to repositories.
- list-collaborators: List the collaborators for repositories and show their permissions you can check yours own too.
- gh secret set <name> -b <value>: Set a secret for repositories.
- gh secret list: List secrets for repositories.

Parameters:
- repofile: Path to a file containing a list of repositories (one per line).
- repolist: A comma-separated list of repositories.
- action: The 'gh' CLI command to execute.
- token: (Optional) GitHub token for authentication.
- owner: The GitHub username whose repositories will be listed.
- outputfile: The file to output the list of repositories. If not specified, the repository list will be output to the console.
- collaborator: The GitHub username of the collaborator to add to the repositories.
- collab_permission: The permission level to assign to the collaborator (e.g., 'read', 'triage', 'write', 'maintain', 'admin').

Examples:
- .\batchrepoaction.ps1 -repofile repofile.txt -action "gh repo view"
- .\batchrepoaction.ps1 -repolist "user/repo1,user/repo2" -action "gh repo view"
- .\batchrepoaction.ps1 -repolist "user/repo1,user/repo2" -action "gh repo view" -token "yourtoken"
- .\batchrepoaction.ps1 -owner "your_github_username" -action "gh repo list" -outputfile repofile.txt
- .\batchrepoaction.ps1 -owner "your_github_username" -action "gh repo list"
- .\batchrepoaction.ps1 -repolist "user/repo1,user/repo2" -action "add-collaborator" -collaborator "collaborator_username" -collab_permission "write"
- .\batchrepoaction.ps1 -repolist "user/repo1,user/repo2" -action "list-collaborators"
- .\batchrepoaction.ps1 -repolist "user/repo1,user/repo2" -action "gh secret set mysecret -b 'valueofsecret'"
- .\batchrepoaction.ps1 -repolist "user/repo1,user/repo2" -action "gh secret list"
"@
}

function Get-Repos {
    param (
        [string]$repofile,
        [string]$repolist
    )

    $repos = @()

    if ($repofile) {
        if (Test-Path $repofile) {
            $repos += Get-Content $repofile
        }
        else {
            Write-Error "File not found: $repofile"
            exit 1
        }
    }

    if ($repolist) {
        $repos += $repolist -split ","
    }

    return $repos
}

function Invoke-Action {
    param (
        [string]$repo,
        [string]$action,
        [string]$token,
        [string]$collaborator,
        [string]$collab_permission
    )

    if ($token) {
        gh auth login --with-token $token
    }

    if ($action -eq "add-collaborator") {
        if (-not $collaborator) {
            Write-Error "Collaborator parameter is required for adding a collaborator."
            exit 1
        }
        if (-not $collab_permission) {
            Write-Error "Collaborator permission parameter is required for adding a collaborator."
            exit 1
        }
        $command = @"
gh api --method PUT -H "Accept: application/vnd.github+json" /repos/$repo/collaborators/$collaborator -f permission=$collab_permission
"@
    }

    elseif ($action -eq "delete-collaborator") {
        if (-not $collaborator) {
            Write-Error "Collaborator parameter is required for deleting a collaborator."
            exit 1
        }
        $command = @"
gh api --method DELETE -H "Accept: application/vnd.github+json" /repos/$repo/collaborators/$collaborator
"@
    }

    elseif ($action -eq "list-collaborators") {
        $command = "gh api /repos/$repo/collaborators --jq '.[] | {login: .login, permission: .permissions}'"
    }

    elseif ($action -match "gh secret set (\S+) -b '?([^']+)'?") {
        $secret_name = $matches[1]
        $secret_value = $matches[2]
        Write-Output "secret, value: $secret_name, $secret_value" | ft -AutoSize
        $command = "gh secret set $secret_name -b '$secret_value' -R $repo"
    }

    elseif ($action -eq "gh secret list") {
        $command = "gh secret list -R $repo"
    }

    else {
        $command = "$action $repo"
    }

    Write-Host "Executing: $command"
    Write-Output "action, repo, token, collaborator, collab_permission: $action, $repo, $token, $collaborator, $collab_permission" | ft -AutoSize
    $result = Invoke-Expression "$command 2>&1"

    if ($LASTEXITCODE -ne 0) {
        Write-Error "Failed to execute command: $command"
        Write-Error "Error: $result"
        return
    }
    elseif ($action -eq "gh secret list" -and (-not $result -or $result.Trim() -eq "")) {
        Write-Host "No secrets found for repository: $repo"
    }
    else {
        Write-Host "Command executed successfully: $command"
        Write-Host $result
        return
    }
}

function Get-ReposList {
    param (
        [string]$owner,
        [string]$outputfile
    )

    $command = "gh repo list $owner -L $maxrepos --json owner,name,visibility,description"
    Write-Host "Executing: $command"
    $result = Invoke-Expression $command | ConvertFrom-Json

    if ($LASTEXITCODE -ne 0) {
        Write-Error "Failed to execute command: $command"
    }
    else {
        Write-Host "Command executed successfully: $command"
        if ($outputfile) {
            $repoList = $result | ForEach-Object { "$($_.owner.login)/$($_.name)" }
            $repoList | Out-File -FilePath $outputfile -Encoding utf8
            Write-Host "Repository list saved to $outputfile"
        }
        else {
            Write-Host "Repository list:"
            $table = @()
            foreach ($repo in $result) {
                $table += [PSCustomObject]@{
                    Name        = $repo.name
                    Visibility  = $repo.visibility
                    Description = $repo.description
                }
            }
            $table | Format-Table -AutoSize
        }
    }
}

# Main script
# Set output encoding to UTF-8 as repo names/desc could contain emojis 
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8

if ($help) {
    Show-Help
    exit 0
}

# Check GitHub CLI authentication status
$authStatus = Invoke-Expression "gh auth status --active 2>&1"

$loggedInUser = $authStatus | Select-String -Pattern "Logged in to github.com account (\w+)" | ForEach-Object {
    if ($_ -match "Logged in to github.com account (\w+)") {
        $matches[1]
    }
}

if ($loggedInUser) {
    Write-Host "GitHub CLI authentication successful. Logged in as: $loggedInUser"
    if (-not $owner) {
        $owner = $loggedInUser
    }
}
else {
    Write-Host "GitHub CLI authentication failed. Please log in using 'gh auth login'."
    return
}

if (-not $action) {
    Write-Error "Action parameter is required."
    exit 1
}

if ($action -eq "gh repo list" -and $owner) {
    Get-ReposList -owner $owner -outputfile $outputfile
    exit 0
}

$repos = Get-Repos -repofile $repofile -repolist $repolist

if ($repos.Count -eq 0) {
    Write-Error "No repositories specified."
    exit 1
}

foreach ($repo in $repos) {
    Invoke-Action -repo $repo -action $action -token $token -collaborator $collaborator -collab_permission $collab_permission
}