#requires -Version 5

[CmdletBinding()]
param(
    [string]$Package,

    [string]$Process,

    [string]$RemoteHost = '127.0.0.1:27042',

    [string]$ScriptPath,

    [switch]$Usb,

    [switch]$Spawn,

    [switch]$Pause,

    [switch]$ListDevices,

    [switch]$ListProcesses
)

Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
[Console]::InputEncoding = [System.Text.UTF8Encoding]::new($false)
[Console]::OutputEncoding = [System.Text.UTF8Encoding]::new($false)
$OutputEncoding = [System.Text.UTF8Encoding]::new($false)

function Get-PythonScriptCandidates {
    param([Parameter(Mandatory = $true)][string]$ExecutableName)

    $roots = @(
        (Join-Path $env:APPDATA 'Python'),
        (Join-Path $env:LOCALAPPDATA 'Programs\Python')
    )

    $candidates = New-Object System.Collections.Generic.List[string]
    foreach ($root in $roots) {
        if (-not (Test-Path -LiteralPath $root)) {
            continue
        }

        $matches = Get-ChildItem -LiteralPath $root -Directory -ErrorAction SilentlyContinue
        foreach ($dir in $matches) {
            $candidate = Join-Path $dir.FullName (Join-Path 'Scripts' $ExecutableName)
            if (Test-Path -LiteralPath $candidate) {
                $candidates.Add($candidate)
            }
        }
    }

    return $candidates
}

function Get-ToolPath {
    param([Parameter(Mandatory = $true)][string]$Name)

    $cmd = Get-Command $Name -ErrorAction SilentlyContinue
    if ($cmd) {
        return $cmd.Source
    }

    foreach ($candidate in Get-PythonScriptCandidates -ExecutableName ($Name + '.exe')) {
        if (Test-Path -LiteralPath $candidate) {
            return $candidate
        }
    }

    # Attempt auto-bootstrap for frida tools
    $bootstrapScript = Join-Path $PSScriptRoot '..\..\scripts\bootstrap-reverse.ps1'
    if (($Name -in @('frida', 'frida-ps', 'frida-ls-devices')) -and (Test-Path -LiteralPath $bootstrapScript)) {
        Write-Host "INFO: $Name not found, attempting auto-bootstrap (pip install frida-tools)..." -ForegroundColor Yellow
        & powershell.exe -NoProfile -ExecutionPolicy Bypass -File $bootstrapScript -Capability @('frida') -SkipRefresh
        $cmd = Get-Command $Name -ErrorAction SilentlyContinue
        if ($cmd) {
            Write-Host "INFO: $Name bootstrapped successfully." -ForegroundColor Green
            return $cmd.Source
        }
        foreach ($candidate in Get-PythonScriptCandidates -ExecutableName ($Name + '.exe')) {
            if (Test-Path -LiteralPath $candidate) {
                return $candidate
            }
        }
    }

    throw "Missing required CLI tool: $Name — install with: pip install frida-tools"
}

$fridaLsDevices = Get-ToolPath -Name 'frida-ls-devices'
$fridaPs = Get-ToolPath -Name 'frida-ps'
$frida = Get-ToolPath -Name 'frida'
$python = Get-Command python -ErrorAction SilentlyContinue

if (-not $python) {
    throw 'Missing required CLI tool: python'
}

$pythonExe = $python.Source

if ($ListDevices) {
    & $pythonExe -c "import frida; [print(f'{d.id}`t{d.type}`t{d.name}') for d in frida.enumerate_devices()]"
    exit $LASTEXITCODE
}

$target = if ($Package) { $Package } elseif ($Process) { $Process } else { '' }
if ([string]::IsNullOrWhiteSpace($target) -and -not $ListProcesses) {
    throw 'Provide -Package or -Process, or use -ListProcesses.'
}

$deviceFlag = if ($Usb) { '-U' } else { '-H' }

if ($ListProcesses) {
    $escapedRemoteHost = $RemoteHost.Replace("'", "''")
    $pythonFlag = if ($Usb) { 'usb' } else { 'remote-host' }
    & $pythonExe -c "import frida; manager = frida.get_device_manager(); device = frida.get_usb_device() if '$pythonFlag' == 'usb' else manager.add_remote_device('$escapedRemoteHost'); [print(f'{p.pid}`t{p.name}') for p in device.enumerate_processes()]"
    exit $LASTEXITCODE
}

if (-not (Test-Path -LiteralPath $ScriptPath)) {
    throw "Frida script not found: $ScriptPath"
}

$fridaArgs = @($deviceFlag)
if (-not $Usb) {
    $fridaArgs += $RemoteHost
}
if ($Spawn) {
    $fridaArgs += '-f'
} else {
    $fridaArgs += '-n'
}
$fridaArgs += $target
$fridaArgs += '-l'
$fridaArgs += $ScriptPath
if (-not $Pause) {
    $fridaArgs += '--no-pause'
}

& $frida @fridaArgs
exit $LASTEXITCODE
