MetaNull.LaravelUtils.psm1

# Module Constants and Initialization

# Icon configuration based on PowerShell version
$script:ModuleIcons = @{}
$script:UseEmojis = $false

# Detect PowerShell version and set icon preference
if ($PSVersionTable.PSVersion.Major -ge 7) {
    # PowerShell 7+ supports Unicode emojis better
    $script:UseEmojis = $true
    $script:ModuleIcons = @{
        # Status Icons
        Rocket = "`u1F680"         # 🚀
        CheckMark = "`u2705"       # ✅
        Warning = "`u26A0"         # ⚠️
        Info = "`u2139"            # ℹ️
        Error = "`u274C"           # ❌

        # Application Icons
        Celebration = "`u1F389"    # 🎉
        MobilePhone = "`u1F4F1"    # 📱
        Satellite = "`u1F4E1"      # 📡
        Lightning = "`u26A1"       # ⚡

        # Tool Icons
        Wrench = "`u1F527"         # 🔧
        Books = "`u1F4DA"          # 📚
        GreenHeart = "`u1F49A"     # 💚
        Key = "`u1F511"            # 🔑
        FloppyDisk = "`u1F4BE"     # 💾

        # Fallback plain text versions
        PlainText = @{
            Rocket = "[START]"
            CheckMark = "[OK]"
            Warning = "[WARN]"
            Info = "[INFO]"
            Error = "[ERROR]"
            Celebration = "[SUCCESS]"
            MobilePhone = "[APP]"
            Satellite = "[API]"
            Lightning = "[HMR]"
            Wrench = "[TOOLS]"
            Books = "[DOCS]"
            GreenHeart = "[HEALTH]"
            Key = "[DASH]"
            FloppyDisk = "[DEV]"
        }
    }
} else {
    # PowerShell 5.1 and earlier - use plain text icons
    $script:UseEmojis = $false
    $script:ModuleIcons = @{
        PlainText = @{
            Rocket = "[START]"
            CheckMark = "[OK]"
            Warning = "[WARN]"
            Info = "[INFO]"
            Error = "[ERROR]"
            Celebration = "[SUCCESS]"
            MobilePhone = "[APP]"
            Satellite = "[API]"
            Lightning = "[HMR]"
            Wrench = "[TOOLS]"
            Books = "[DOCS]"
            GreenHeart = "[HEALTH]"
            Key = "[DASH]"
            FloppyDisk = "[DEV]"
        }
    }
}

# Color constants for consistent output
Set-Variable -Name "ModuleColorSuccess" -Value "Green" -Option Constant
Set-Variable -Name "ModuleColorWarning" -Value "Yellow" -Option Constant
Set-Variable -Name "ModuleColorError" -Value "Red" -Option Constant
Set-Variable -Name "ModuleColorInfo" -Value "Cyan" -Option Constant
Set-Variable -Name "ModuleColorStep" -Value "Magenta" -Option Constant
Set-Variable -Name "ModuleColorHeader" -Value "White" -Option Constant
Function Get-DevIcon {
<#
    .SYNOPSIS
    Gets an icon for display based on PowerShell version capabilities
 
    .DESCRIPTION
    Returns either an emoji icon (PowerShell 7+) or plain text fallback (PowerShell 5.1).
    This is a public wrapper around the private Get-ModuleIcon function.
 
    .PARAMETER IconName
    The name of the icon to retrieve. Valid values include:
    Rocket, CheckMark, Warning, Info, Error, Celebration, MobilePhone,
    Satellite, Lightning, Wrench, Books, GreenHeart, Key, FloppyDisk
 
    .OUTPUTS
    String - The icon character or text representation
 
    .EXAMPLE
    Get-DevIcon "Rocket"
    Returns "🚀" on PowerShell 7+ or "[START]" on PowerShell 5.1
 
    .EXAMPLE
    $icon = Get-DevIcon "CheckMark"
    Write-Host "$icon Operation completed successfully!"
#>

[CmdletBinding()]
[OutputType([string])]
param(
    [Parameter(Mandatory = $true, Position = 0)]
    [ValidateSet("Rocket", "CheckMark", "Warning", "Info", "Error", "Celebration",
                 "MobilePhone", "Satellite", "Lightning", "Wrench", "Books",
                 "GreenHeart", "Key", "FloppyDisk")]
    [string]$IconName
)

End {
    return Get-ModuleIcon -IconName $IconName
}
}
Function Get-ModuleIcon {
<#
    .SYNOPSIS
    Gets an icon for display based on PowerShell version capabilities
 
    .DESCRIPTION
    Returns either an emoji icon (PowerShell 7+) or plain text fallback (PowerShell 5.1)
 
    .PARAMETER IconName
    The name of the icon to retrieve
 
    .EXAMPLE
    Get-ModuleIcon "Rocket"
    Returns "`u{1F680}" on PowerShell 7+ or "[START]" on PowerShell 5.1
#>

[CmdletBinding()]
[OutputType([string])]
param(
    [Parameter(Mandatory = $true, Position = 0)]
    [string]$IconName,

    [Parameter()]
    [ValidateSet("plaintext", "unicode", "auto")]
    [string]$Mode = "auto"
)

End {
    if ($Mode -eq "plaintext" -or ($Mode -eq "auto" -and -not $script:UseEmojis)) {
        $PlainText = $true
    }
    elseif ($Mode -eq "unicode") {
        $PlainText = $false
    }
    else {
        $PlainText = $script:UseEmojis -eq $false
    }
    if ($PlainText) {
        $IconSet = $script:ModuleIcons.PlainText
    }
    else {
        $IconSet = $script:ModuleIcons
    }
    if ($IconSet.ContainsKey($IconName)) {
        return $IconSet[$IconName]
    }
    else {
        Write-Warning "Icon '$IconName' not found."
    }
    return "?"
}
}
Function Stop-DevProcessOnPort {
<#
    .SYNOPSIS
    Stops processes running on a specific port
 
    .DESCRIPTION
    Finds and forcefully stops all processes that are listening on the specified port.
    Useful for freeing up ports before starting development servers.
 
    .PARAMETER Port
    The port number to free up
 
    .EXAMPLE
    Stop-DevProcessOnPort -Port 8000
    Stops all processes using port 8000
#>

[CmdletBinding()]
param(
    [Parameter(Mandatory = $true)]
    [int]$Port
)

End {
    try {
        $processes = Get-NetTCPConnection -LocalPort $Port -ErrorAction SilentlyContinue |
                    Select-Object -ExpandProperty OwningProcess -Unique

        foreach ($processId in $processes) {
            if ($processId -and $processId -ne 0) {
                $process = Get-Process -Id $processId -ErrorAction SilentlyContinue
                if ($process) {
                    Write-Development -Message "Stopping process $($process.Name) (PID: $processId) on port $Port" -Type Warning
                    Stop-Process -Id $processId -Force
                    Start-Sleep -Seconds 1
                }
            }
        }
    } catch {
        # Ignore errors when stopping processes
        Write-Development -Message "Could not stop processes on port $Port - they may have already been stopped" -Type Warning
    }
}
}
Function Test-DevCommand {
<#
    .SYNOPSIS
    Tests if a command is available in the current session
 
    .DESCRIPTION
    Checks if a command exists and can be executed in the current PowerShell session
 
    .PARAMETER Command
    The command name to test
 
    .OUTPUTS
    Boolean - True if command exists, False otherwise
 
    .EXAMPLE
    Test-DevCommand "php"
    Returns $true if PHP is available in PATH
#>

[CmdletBinding()]
[OutputType([bool])]
param(
    [Parameter(Mandatory = $true)]
    [string]$Command
)

End {
    try {
        $null = Get-Command $Command -ErrorAction Stop
        return $true
    } catch {
        return $false
    }
}
}
Function Test-DevPort {
<#
    .SYNOPSIS
    Tests if a TCP port is open and accepting connections
 
    .DESCRIPTION
    Uses a TCP client to test if a port is available on localhost (127.0.0.1).
    This approach avoids IPv6 warnings that can occur with Test-NetConnection.
 
    .PARAMETER Port
    The port number to test
 
    .OUTPUTS
    Boolean - True if port is in use, False if available
 
    .EXAMPLE
    Test-DevPort 8000
    Returns $true if port 8000 is in use, $false if available
#>

[CmdletBinding()]
[OutputType([bool])]
param(
    [Parameter(Mandatory = $true)]
    [int]$Port
)

End {
    try {
        # Use a TCP client approach which is more reliable and doesn't show IPv6 warnings
        $tcpClient = New-Object System.Net.Sockets.TcpClient
        $tcpClient.ReceiveTimeout = 1000
        $tcpClient.SendTimeout = 1000
        $result = $tcpClient.BeginConnect("127.0.0.1", $Port, $null, $null)
        $success = $result.AsyncWaitHandle.WaitOne(1000, $false)

        if ($success) {
            try {
                $tcpClient.EndConnect($result)
                $tcpClient.Close()
                return $true
            } catch {
                $tcpClient.Close()
                return $false
            }
        } else {
            $tcpClient.Close()
            return $false
        }
    } catch {
        return $false
    }
}
}
Function Test-LaravelPath {
<#
    .SYNOPSIS
    Tests if the directory is the root of a Laravel application
     
    .DESCRIPTION
    Checks if the specified path contains a Laravel application by looking for key files and directories
     
    .PARAMETER Path
    The root directory of the Laravel application
     
    .EXAMPLE
    Test-LaravelPath -Path "C:\path\to\laravel"
    Tests if the specified path is a Laravel application root
#>

[CmdletBinding()]
param(
    [Parameter(Mandatory = $true, Position = 0)]
    [string]$Path = '.'
)

Begin {
    if(-Not (Test-Path -Path $Path -PathType Container)) {
        Write-Development -Message "The specified path '$Path' does not exist or is not a directory." -Type Error
        return $false
    }
    if(-Not (Test-Path -Path (Join-Path -Path $Path -ChildPath 'artisan'))) {
        Write-Development -Message "The specified path '$Path' does not contain a Laravel application (missing 'artisan' file)." -Type Error
        return $false
    }
    if(-Not (Test-Path -Path (Join-Path -Path $Path -ChildPath 'composer.json'))) {
        Write-Development -Message "The specified path '$Path' does not contain a Laravel application (missing 'composer.json' file)." -Type Error
        return $false
    }
    if(-Not (Test-Path -Path (Join-Path -Path $Path -ChildPath 'vendor'))) {
        Write-Development -Message "The specified path '$Path' does not contain a Laravel application (missing 'vendor' directory). Please run 'composer install' first." -Type Error
        return $false
    }
    if(-Not (Test-Path -Path (Join-Path -Path $Path -ChildPath 'package.json'))) {
        Write-Development -Message "The specified path '$Path' does not contain a Laravel application (missing 'package.json' file)." -Type Error
        return $false
    }
    if(-Not (Test-Path -Path (Join-Path -Path $Path -ChildPath 'vite.config.js'))) {
        Write-Development -Message "The specified path '$Path' does not contain a Laravel application (missing 'vite.config.js' file)." -Type Error
        return $false
    }
    if(-Not (Test-Path -Path (Join-Path -Path $Path -ChildPath 'node_modules'))) {
        Write-Development -Message "The specified path '$Path' does not contain a Laravel application (missing 'node_modules' directory). Please run 'npm install' first." -Type Error
        return $false
    }
    return $true
}
}
Function Wait-ForDevPort {
<#
    .SYNOPSIS
    Waits for a port to become available (in use) with timeout
 
    .DESCRIPTION
    Continuously tests a port until it becomes available or timeout is reached.
    Useful for waiting for servers to start up.
 
    .PARAMETER Port
    The port number to wait for
 
    .PARAMETER TimeoutSeconds
    Maximum time to wait in seconds (default: 10)
 
    .PARAMETER IntervalSeconds
    Time between checks in seconds (default: 1)
 
    .OUTPUTS
    Boolean - True if port became available within timeout, False otherwise
 
    .EXAMPLE
    Wait-ForDevPort -Port 8000 -TimeoutSeconds 30
    Waits up to 30 seconds for port 8000 to become available
#>

[CmdletBinding()]
[OutputType([bool])]
param(
    [Parameter(Mandatory = $true)]
    [int]$Port,

    [Parameter(Mandatory = $false)]
    [int]$TimeoutSeconds = 10,

    [Parameter(Mandatory = $false)]
    [int]$IntervalSeconds = 1
)

End {
    $elapsed = 0
    while ($elapsed -lt $TimeoutSeconds) {
        if (Test-DevPort -Port $Port) {
            return $true
        }
        Start-Sleep -Seconds $IntervalSeconds
        $elapsed += $IntervalSeconds
    }
    return $false
}
}
Function Write-Development {
<#
    .SYNOPSIS
    Writes a development message with appropriate icon and color
 
    .DESCRIPTION
    Displays a message for development utilities with icon and color based on type
 
    .PARAMETER Message
    The message to display
 
    .PARAMETER Type
    The type of message (Info, Error, Success, Warning, Step, Header). Default is Info.
 
    .EXAMPLE
    Write-Development -Message "Server started successfully!" -Type Success
 
    .EXAMPLE
    Write-Development -Message "An error occurred while starting the server." -Type Error
 
    .EXAMPLE
    Write-Development -Message "This is an information message."
#>

[CmdletBinding()]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWriteHost', '', Justification = 'Write-Host is appropriate for colored user output in development utilities')]
param(
    [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)]
    [AllowNull()]
    [AllowEmptyString()]
    [string]$Message,

    [ValidateSet('Info','Error','Success','Warning','Step','Header')]
    [string]$Type = 'Info'
)

Process {
    switch ($Type) {
        'Error'   { $icon = Get-ModuleIcon 'Error';       $color = $script:ModuleColorError }
        'Success' { $icon = Get-ModuleIcon 'CheckMark';   $color = $script:ModuleColorSuccess }
        'Warning' { $icon = Get-ModuleIcon 'Warning';     $color = $script:ModuleColorWarning }
        'Step'    { $icon = Get-ModuleIcon 'Rocket';      $color = $script:ModuleColorStep }
        'Header'  { $icon = Get-ModuleIcon 'Celebration'; $color = $script:ModuleColorHeader }
        default   { $icon = Get-ModuleIcon 'Info';        $color = $script:ModuleColorInfo }
    }

    if($Type -in @('Header')) {
        Write-Host ""
        Write-Host "$icon $Message" -ForegroundColor $color
        Write-Host ""
    } else {
        Write-Host "$icon $Message" -ForegroundColor $color
    }
    
}
}
Function Start-Laravel {
<#
    .SYNOPSIS
    Starts the complete Laravel development environment
 
    .DESCRIPTION
    Starts all Laravel development components: Web server, Vite, and Queue workers
 
    .PARAMETER Path
    The root directory of the Laravel application
 
    .PARAMETER WebPort
    Port for the Laravel web server (default: 8000)
 
    .PARAMETER VitePort
    Port for the Vite development server (default: 5173)
 
    .PARAMETER Queue
    Queue name for Laravel queue workers (default: "default")
 
    .PARAMETER TimeoutSeconds
    Timeout in seconds for server startup checks (default: 30)
 
    .PARAMETER Force
    Force stop any existing processes on the specified ports
 
    .EXAMPLE
    Start-Laravel -Path "C:\path\to\laravel"
    Starts Laravel with default settings (web on 8000, vite on 5173, default queue)
 
    .EXAMPLE
    Start-Laravel -Path "C:\path\to\laravel" -WebPort 8080 -VitePort 3000 -Queue "emails" -Force
    Starts Laravel with custom ports and queue, forcing stop of existing processes
#>

[CmdletBinding()]
param(
    [Parameter()]
    [ValidateScript({ Test-LaravelPath -Path $_ })]
    [string]$Path = '.',

    [Parameter()]
    [int]$WebPort = 8000,

    [Parameter()]
    [int]$VitePort = 5173,

    [Parameter()]
    [string]$Queue = "default",

    [Parameter()]
    [int]$TimeoutSeconds = 30,

    [Parameter()]
    [switch]$Force
)

Begin {
    Write-Development -Message "Starting Laravel Development Environment" -Type Header

    $success = $true

    try {
        # Start Laravel Web Server
        Write-Development -Message "Starting Laravel web server..." -Type Info
        $webResult = Start-LaravelWeb -Path $Path -Port $WebPort -TimeoutSeconds $TimeoutSeconds -Force:$Force
        if (-not $webResult) {
            Write-Development -Message "Failed to start Laravel web server" -Type Error
            $success = $false
        }

        # Start Vite Development Server
        Write-Development -Message "Starting Vite development server..." -Type Info
        $viteResult = Start-LaravelVite -Path $Path -Port $VitePort -LaravelPort $WebPort -TimeoutSeconds $TimeoutSeconds -Force:$Force
        if (-not $viteResult) {
            Write-Development -Message "Failed to start Vite development server" -Type Error
            $success = $false
        }

        # Start Laravel Queue Worker
        Write-Development -Message "Starting Laravel queue worker..." -Type Info
        $queueResult = Start-LaravelQueue -Path $Path -Queue $Queue -Force:$Force
        if (-not $queueResult) {
            Write-Development -Message "Failed to start Laravel queue worker" -Type Error
            $success = $false
        }

        if ($success) {
            Write-Development -Message "Laravel development environment started successfully!" -Type Success
            Write-Development -Message "Services:" -Type Info
            Write-Development -Message " - Web Server: http://localhost:$WebPort" -Type Info
            Write-Development -Message " - Vite Server: http://localhost:$VitePort" -Type Info
            Write-Development -Message " - Queue Worker: $Queue queue" -Type Info
        } else {
            Write-Development -Message "Some Laravel services failed to start. Check the logs above." -Type Warning
        }

        return $success

    } catch {
        Write-Development -Message "Failed to start Laravel development environment: $($_.Exception.Message)" -Type Error
        return $false
    }
}
}
Function Start-LaravelQueue {
<#
    .SYNOPSIS
    Starts the Laravel queue worker
     
    .DESCRIPTION
    Starts Laravel's queue worker to process background jobs
     
    .PARAMETER Path
    The root directory of the Laravel application
     
    .PARAMETER Queue
    The queue name to process (default: default)
     
    .PARAMETER ConnectionName
    The queue connection to use (default: uses Laravel's default)
     
    .PARAMETER MaxJobs
    Maximum number of jobs to process before restarting (default: 1000)
     
    .PARAMETER MaxTime
    Maximum time in seconds the worker should run (default: 3600)
     
    .PARAMETER Sleep
    Number of seconds to sleep when no jobs are available (default: 3)
     
    .PARAMETER Timeout
    Number of seconds a child process can run (default: 60)
     
    .PARAMETER Force
    Force stop any existing queue workers
     
    .EXAMPLE
    Start-LaravelQueue -Path "C:\path\to\laravel"
    Starts Laravel queue worker with default settings
     
    .EXAMPLE
    Start-LaravelQueue -Path "C:\path\to\laravel" -Queue "emails" -MaxJobs 500
    Starts Laravel queue worker for the "emails" queue with max 500 jobs
#>

[CmdletBinding()]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', 'Path', Justification = 'Used via $Using:Path in Start-Job ScriptBlock')]
param(
    [Parameter()]
    [ValidateScript({ Test-LaravelPath -Path $_ })]
    [string]$Path = '.',
    
    [Parameter()]
    [string]$Queue = "default",
    
    [Parameter()]
    [string]$ConnectionName,
    
    [Parameter()]
    [int]$MaxJobs = 1000,
    
    [Parameter()]
    [int]$MaxTime = 3600,
    
    [Parameter()]
    [int]$Sleep = 3,
    
    [Parameter()]
    [int]$Timeout = 60,
    
    [Parameter()]
    [switch]$Force
)

Begin {
    Write-Development -Message "Starting Laravel queue worker for queue '$Queue'..." -Type Step
    
    if ($Force) {
        Write-Development -Message "Stopping any existing queue workers..." -Type Info
        Stop-LaravelQueue -Queue $Queue -Force
    }
    
    # Build the artisan command
    $queueCommand = "queue:work"
    $queueArgs = @()
    
    if ($ConnectionName) {
        $queueArgs += $ConnectionName
    }
    
    $queueArgs += "--queue=$Queue"
    $queueArgs += "--max-jobs=$MaxJobs"
    $queueArgs += "--max-time=$MaxTime"
    $queueArgs += "--sleep=$Sleep"
    $queueArgs += "--timeout=$Timeout"
    $queueArgs += "--verbose"
    
    # Start queue worker
    $queueJob = Start-Job -ScriptBlock {
        Set-Location $Using:Path
        & php artisan $Using:queueCommand $Using:queueArgs
    }
    
    # Give it a moment to start
    Start-Sleep -Seconds 2
    
    # Check if job is running
    if ($queueJob.State -eq "Running") {
        Write-Development -Message "Laravel queue worker started successfully for queue '$Queue'" -Type Success
        Write-Development -Message "Worker will process up to $MaxJobs jobs or run for $MaxTime seconds" -Type Info
        return $queueJob
    } else {
        Write-Development -Message "Failed to start Laravel queue worker" -Type Error
        
        # Get job output for debugging
        $jobOutput = Receive-Job $queueJob -ErrorAction SilentlyContinue
        if ($jobOutput) {
            Write-Development -Message "Queue worker output: $jobOutput" -Type Error
        }
        
        Remove-Job $queueJob -ErrorAction SilentlyContinue
        return $null
    }
}
}
Function Start-LaravelVite {
<#
    .SYNOPSIS
    Starts the Laravel Vite development server
     
    .DESCRIPTION
    Starts the Vite development server for Laravel frontend assets
     
    .PARAMETER Path
    The root directory of the Laravel application
     
    .PARAMETER Port
    The port number to start the Vite server on (default: 5173)
     
    .PARAMETER LaravelPort
    The Laravel web server port for proper integration (default: 8000)
     
    .PARAMETER TimeoutSeconds
    How long to wait for the server to start (default: 15)
     
    .PARAMETER Force
    Force stop any existing processes on the specified port
     
    .EXAMPLE
    Start-LaravelVite -Path "C:\path\to\laravel" -Port 5173 -LaravelPort 8000
    Starts Vite server on port 5173 integrated with Laravel on port 8000
#>

[CmdletBinding()]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', 'Path', Justification = 'Used via $Using:Path in Start-Job ScriptBlock')]
param(
    [Parameter()]
    [ValidateScript({ Test-LaravelPath -Path $_})]
    [string]$Path = '.',
    
    [Parameter()]
    [int]$Port = 5173,
    
    [Parameter()]
    [int]$LaravelPort = 8000,
    
    [Parameter()]
    [int]$TimeoutSeconds = 15,
    
    [Parameter()]
    [switch]$Force
)

Begin {
    Write-Development -Message "Starting Laravel Vite server on port $Port..." -Type Step
    
    # Check if port is available
    if (Test-DevPort -Port $Port) {
        if ($Force) {
            Write-Development -Message "Port $Port is already in use. Force stopping processes..." -Type Warning
            Stop-DevProcessOnPort -Port $Port
            Start-Sleep -Seconds 2
        }
        
        if (Test-DevPort -Port $Port) {
            Write-Development -Message "Unable to free port $Port. Please check what's using it and try again." -Type Error
            return $null
        }
    }
    
    # Start Vite server with output redirection to prevent job termination
    $viteJob = Start-Job -ScriptBlock {
        Set-Location $Using:Path
        
        # Set environment variables for Vite to ensure IPv4 binding
        $env:VITE_PORT = $Using:Port
        $env:VITE_HOST = "127.0.0.1"
        $env:VITE_DEV_SERVER_URL = "http://127.0.0.1:$($Using:Port)"
        
        # Start Vite with port specification using npx directly for proper argument handling
        npx vite --host 127.0.0.1 --port $Using:Port --strictPort 2>&1
    }
    
    # Wait longer for Vite to start (it takes more time than Laravel)
    Write-Development -Message "Waiting for Laravel Vite server to start (timeout: $TimeoutSeconds seconds)..." -Type Info
    if (Wait-ForDevPort -Port $Port -TimeoutSeconds $TimeoutSeconds) {
        Write-Development -Message "Laravel Vite server running at http://127.0.0.1:$Port" -Type Success
        Write-Development -Message "Note: Access your Vue app via Laravel at http://127.0.0.1:$LaravelPort/" -Type Info
        return $viteJob
    } else {
        Write-Development -Message "Failed to start Laravel Vite server within $TimeoutSeconds seconds" -Type Error
        if ($viteJob) {
            # Get job output for debugging
            Start-Sleep -Seconds 2  # Give job time to produce output
            $jobOutput = Receive-Job $viteJob -ErrorAction SilentlyContinue
            if ($jobOutput) {
                Write-Development -Message "Vite job output: $jobOutput" -Type Error
            }
            
            # Also check job state and errors
            if ($viteJob.State -eq "Failed") {
                $jobErrors = $viteJob.ChildJobs[0].Error
                if ($jobErrors) {
                    Write-Development -Message "Vite job errors: $jobErrors" -Type Error
                }
            }
            
            Stop-Job $viteJob -ErrorAction SilentlyContinue
            Remove-Job $viteJob -ErrorAction SilentlyContinue
        }
        return $null
    }
}
}
Function Start-LaravelWeb {
<#
    .SYNOPSIS
    Starts the Laravel web development server
     
    .DESCRIPTION
    Starts the Laravel artisan serve command on the specified port with proper error handling
     
    .PARAMETER Path
    The root directory of the Laravel application
     
    .PARAMETER Port
    The port number to start the Laravel server on (default: 8000)
     
    .PARAMETER TimeoutSeconds
    How long to wait for the server to start (default: 10)
     
    .PARAMETER Force
    Force stop any existing processes on the specified port
     
    .EXAMPLE
    Start-LaravelWeb -Path "C:\path\to\laravel" -Port 8000
    Starts Laravel web server on port 8000
     
    .EXAMPLE
    Start-LaravelWeb -Path "C:\path\to\laravel" -Port 8001 -TimeoutSeconds 15
    Starts Laravel web server on port 8001 with 15 second timeout
#>

[CmdletBinding()]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', 'Path', Justification = 'Used via $Using:Path in Start-Job ScriptBlock')]
param(
    [Parameter()]
    [ValidateScript({ Test-LaravelPath -Path $_})]
    [string]$Path = '.',
    
    [Parameter()]
    [int]$Port = 8000,
    
    [Parameter()]
    [int]$TimeoutSeconds = 10,
    
    [Parameter()]
    [switch]$Force
)

Begin {
    Write-Development -Message "Starting Laravel web server on port $Port..." -Type Step
    
    # Check if port is available
    if (Test-DevPort -Port $Port) {
        if ($Force) {
            Write-Development -Message "Port $Port is already in use. Force stopping processes..." -Type Warning
            Stop-DevProcessOnPort -Port $Port
            Start-Sleep -Seconds 2
        }
        
        if (Test-DevPort -Port $Port) {
            Write-Development -Message "Unable to free port $Port. Please check what's using it and try again." -Type Error
            return $null
        }
    }
    
    # Start Laravel server
    $laravelJob = Start-Job -ScriptBlock {
        Set-Location $Using:Path
        php artisan serve --port=$Using:Port --host=127.0.0.1
    }
    
    # Wait for server to start with configurable timeout
    Write-Development -Message "Waiting for Laravel web server to start (timeout: $TimeoutSeconds seconds)..." -Type Info
    if (Wait-ForDevPort -Port $Port -TimeoutSeconds $TimeoutSeconds) {
        Write-Development -Message "Laravel web server running at http://127.0.0.1:$Port" -Type Success
        return $laravelJob
    } else {
        Write-Development -Message "Failed to start Laravel web server within $TimeoutSeconds seconds" -Type Error
        
        # Get job output for debugging
        Start-Sleep -Seconds 1
        $jobOutput = Receive-Job $laravelJob -ErrorAction SilentlyContinue
        if ($jobOutput) {
            Write-Development -Message "Laravel job output: $jobOutput" -Type Error
        }
        
        if ($laravelJob) {
            Stop-Job $laravelJob -ErrorAction SilentlyContinue
            Remove-Job $laravelJob -ErrorAction SilentlyContinue
        }
        return $null
    }
}
}
Function Stop-Laravel {
<#
    .SYNOPSIS
    Stops the complete Laravel development environment
     
    .DESCRIPTION
    Stops all Laravel development components: Web server, Vite, and Queue workers
     
    .PARAMETER Path
    The root directory of the Laravel application
     
    .PARAMETER WebPort
    Port for the Laravel web server (default: 8000)
     
    .PARAMETER VitePort
    Port for the Vite development server (default: 5173)
     
    .PARAMETER Queue
    Queue name for Laravel queue workers (optional - stops all if not specified)
     
    .PARAMETER Force
    Force stop processes without graceful shutdown
     
    .EXAMPLE
    Stop-Laravel
    Stops all Laravel services with default settings
     
    .EXAMPLE
    Stop-Laravel -WebPort 8080 -VitePort 3000 -Queue "emails" -Force
    Forcefully stops Laravel services with custom ports and specific queue
#>

[CmdletBinding()]
param(
    [Parameter()]
    [int]$WebPort = 8000,
    
    [Parameter()]
    [int]$VitePort = 5173,
    
    [Parameter()]
    [string]$Queue,
    
    [Parameter()]
    [switch]$Force
)

Begin {
    Write-Development -Message "Stopping Laravel Development Environment" -Type Header
    
    $success = $true
    
    try {
        # Stop Laravel Web Server
        Write-Development -Message "Stopping Laravel web server..." -Type Info
        $webResult = Stop-LaravelWeb -Port $WebPort -Force:$Force
        if (-not $webResult) {
            Write-Development -Message "Issues stopping Laravel web server" -Type Warning
            $success = $false
        }
        
        # Stop Vite Development Server
        Write-Development -Message "Stopping Vite development server..." -Type Info
        $viteResult = Stop-LaravelVite -Port $VitePort -Force:$Force
        if (-not $viteResult) {
            Write-Development -Message "Issues stopping Vite development server" -Type Warning
            $success = $false
        }
        
        # Stop Laravel Queue Worker
        Write-Development -Message "Stopping Laravel queue worker..." -Type Info
        if ($Queue) {
            $queueResult = Stop-LaravelQueue -Queue $Queue -Force:$Force
        } else {
            $queueResult = Stop-LaravelQueue -Force:$Force
        }
        if (-not $queueResult) {
            Write-Development -Message "Issues stopping Laravel queue worker" -Type Warning
            $success = $false
        }
        
        if ($success) {
            Write-Development -Message "Laravel development environment stopped successfully!" -Type Success
        } else {
            Write-Development -Message "Some Laravel services may still be running. Check the logs above." -Type Warning
        }
        
        return $success
        
    } catch {
        Write-Development -Message "Failed to stop Laravel development environment: $($_.Exception.Message)" -Type Error
        return $false
    }
}
}
Function Stop-LaravelQueue {
<#
    .SYNOPSIS
    Stops the Laravel queue worker
     
    .DESCRIPTION
    Stops Laravel queue worker processes gracefully
     
    .PARAMETER Path
    The root directory of the Laravel application
     
    .PARAMETER Force
    Force stop without confirmation
     
    .PARAMETER Queue
    Specific queue name to target (optional)
     
    .EXAMPLE
    Stop-LaravelQueue
    Stops all Laravel queue workers
     
    .EXAMPLE
    Stop-LaravelQueue -Queue "emails" -Force
    Force stops Laravel queue workers for the "emails" queue
#>

[CmdletBinding()]
param(
    [Parameter()]
    [switch]$Force,
    
    [Parameter()]
    [string]$Queue
)

Begin {
    Write-Development -Message "Stopping Laravel queue worker$(if($Queue) { " for queue '$Queue'" })..." -Type Step
    
    try {
        # Find queue worker processes
        $queueProcesses = Get-Process | Where-Object {
            $_.ProcessName -match "php" -and 
            $_.CommandLine -match "artisan.*queue:work"
        }
        
        if ($Queue) {
            $queueProcesses = $queueProcesses | Where-Object {
                $_.CommandLine -match "queue.*$Queue"
            }
        }
        
        if (-not $queueProcesses) {
            Write-Development -Message "No Laravel queue worker processes found$(if($Queue) { " for queue '$Queue'" })" -Type Info
            return $true
        }
        
        $stoppedAny = $false
        
        foreach ($process in $queueProcesses) {
            if (-not $Force) {
                $confirmation = Read-Host "Stop Laravel queue worker process (PID: $($process.Id))? [Y/n]"
                if ($confirmation -eq "n" -or $confirmation -eq "N") {
                    Write-Development -Message "Skipping process $($process.Id)" -Type Info
                    continue
                }
            }
            
            Write-Development -Message "Stopping Laravel queue worker process (PID: $($process.Id))" -Type Step
            
            try {
                # Try graceful stop first
                $process.CloseMainWindow()
                Start-Sleep -Seconds 3
                
                # Check if process is still running
                $runningProcess = Get-Process -Id $process.Id -ErrorAction SilentlyContinue
                if ($runningProcess) {
                    # Force kill if still running
                    Stop-Process -Id $process.Id -Force
                    Start-Sleep -Seconds 1
                }
                
                Write-Development -Message "Stopped Laravel queue worker (PID: $($process.Id))" -Type Success
                $stoppedAny = $true
                
            } catch {
                Write-Development -Message "Failed to stop process $($process.Id)`: $($_.Exception.Message)" -Type Error
            }
        }
        
        if ($stoppedAny) {
            Write-Development -Message "Laravel queue worker$(if($Queue) { "s for queue '$Queue'" }) stopped successfully" -Type Success
            return $true
        } else {
            Write-Development -Message "No Laravel queue workers were stopped" -Type Warning
            return $false
        }
        
    } catch {
        Write-Development -Message "Failed to stop Laravel queue worker: $($_.Exception.Message)" -Type Error
        return $false
    }
}
}
Function Stop-LaravelVite {
<#
    .SYNOPSIS
    Stops the Laravel Vite development server
     
    .DESCRIPTION
    Stops processes running on the Laravel Vite server port
     
    .PARAMETER Path
    The root directory of the Laravel application
     
    .PARAMETER Port
    The port number where Laravel Vite server is running (default: 5173)
     
    .PARAMETER Force
    Force stop without confirmation
     
    .EXAMPLE
    Stop-LaravelVite -Port 5173
    Stops Laravel Vite server on port 5173
     
    .EXAMPLE
    Stop-LaravelVite -Force
    Force stops Laravel Vite server with default port
#>

[CmdletBinding()]
param(
    [Parameter()]
    [int]$Port = 5173,
    
    [Parameter()]
    [switch]$Force
)

Begin {
    Write-Development -Message "Stopping Laravel Vite server on port $Port..." -Type Step
    
    try {
        if (-not (Test-DevPort -Port $Port)) {
            Write-Development -Message "Laravel Vite server is not running on port $Port" -Type Info
            return $true
        }
        
        # Get processes using the port
        $processes = Get-NetTCPConnection -LocalPort $Port -ErrorAction SilentlyContinue | 
                    Select-Object -ExpandProperty OwningProcess -Unique
        
        if (-not $processes) {
            Write-Development -Message "Port $Port appears to be in use but no processes found" -Type Warning
            return $false
        }
        
        $stoppedAny = $false
        
        foreach ($processId in $processes) {
            if ($processId -and $processId -ne 0) {
                $process = Get-Process -Id $processId -ErrorAction SilentlyContinue
                if ($process) {
                    # Verify this is likely a Vite server process
                    $isViteProcess = $process.ProcessName -match "(node|npm)" -or 
                                   $process.CommandLine -match "(vite|npm.*dev)"
                    
                    if ($isViteProcess -or $Force) {
                        if (-not $Force) {
                            $confirmation = Read-Host "Stop Laravel Vite process '$($process.Name)' (PID: $processId)? [Y/n]"
                            if ($confirmation -eq "n" -or $confirmation -eq "N") {
                                Write-Development -Message "Skipping process $processId" -Type Info
                                continue
                            }
                        }
                        
                        Write-Development -Message "Stopping Laravel Vite process '$($process.Name)' (PID: $processId)" -Type Step
                        
                        try {
                            # Try graceful stop first
                            $process.CloseMainWindow()
                            Start-Sleep -Seconds 2
                            
                            # Check if process is still running
                            $runningProcess = Get-Process -Id $processId -ErrorAction SilentlyContinue
                            if ($runningProcess) {
                                # Force kill if still running
                                Stop-Process -Id $processId -Force
                                Start-Sleep -Seconds 1
                            }
                            
                            Write-Development -Message "Stopped Laravel Vite server (PID: $processId)" -Type Success
                            $stoppedAny = $true
                            
                        } catch {
                            Write-Development -Message "Failed to stop process $processId`: $($_.Exception.Message)" -Type Error
                        }
                    } else {
                        Write-Development -Message "Process '$($process.Name)' (PID: $processId) on port $Port doesn't appear to be a Laravel Vite server" -Type Warning
                        Write-Development -Message "Use -Force to stop it anyway" -Type Info
                    }
                }
            }
        }
        
        # Verify port is now free
        Start-Sleep -Seconds 1
        if (-not (Test-DevPort -Port $Port)) {
            if ($stoppedAny) {
                Write-Development -Message "Laravel Vite server stopped successfully" -Type Success
            }
            return $true
        } else {
            Write-Development -Message "Laravel Vite port $Port is still in use after attempting to stop processes" -Type Warning
            return $false
        }
        
    } catch {
        Write-Development -Message "Failed to stop Laravel Vite server on port $Port`: $($_.Exception.Message)" -Type Error
        return $false
    }
}
}
Function Stop-LaravelWeb {
<#
    .SYNOPSIS
    Stops the Laravel web development server
     
    .DESCRIPTION
    Stops processes running on the Laravel web server port
     
    .PARAMETER Path
    The root directory of the Laravel application
     
    .PARAMETER Port
    The port number where Laravel web server is running (default: 8000)
     
    .PARAMETER Force
    Force stop without confirmation
     
    .EXAMPLE
    Stop-LaravelWeb -Port 8000
    Stops Laravel web server on port 8000
     
    .EXAMPLE
    Stop-LaravelWeb -Port 8001 -Force
    Force stops Laravel web server on port 8001
#>

[CmdletBinding()]
param(
    [Parameter()]
    [int]$Port = 8000,
    
    [Parameter()]
    [switch]$Force
)

Begin {
    Write-Development -Message "Stopping Laravel web server on port $Port..." -Type Step
    
    try {
        if (-not (Test-DevPort -Port $Port)) {
            Write-Development -Message "Laravel web server is not running on port $Port" -Type Info
            return $true
        }
        
        # Get processes using the port
        $processes = Get-NetTCPConnection -LocalPort $Port -ErrorAction SilentlyContinue | 
                    Select-Object -ExpandProperty OwningProcess -Unique
        
        if (-not $processes) {
            Write-Development -Message "Port $Port appears to be in use but no processes found" -Type Warning
            return $false
        }
        
        $stoppedAny = $false
        
        foreach ($processId in $processes) {
            if ($processId -and $processId -ne 0) {
                $process = Get-Process -Id $processId -ErrorAction SilentlyContinue
                if ($process) {
                    # Verify this is likely a Laravel web server process
                    $isLaravelProcess = $process.ProcessName -match "(php|artisan)" -or 
                                      $process.CommandLine -match "artisan serve"
                    
                    if ($isLaravelProcess -or $Force) {
                        if (-not $Force) {
                            $confirmation = Read-Host "Stop Laravel web process '$($process.Name)' (PID: $processId)? [Y/n]"
                            if ($confirmation -eq "n" -or $confirmation -eq "N") {
                                Write-Development -Message "Skipping process $processId" -Type Info
                                continue
                            }
                        }
                        
                        Write-Development -Message "Stopping Laravel web process '$($process.Name)' (PID: $processId)" -Type Step
                        
                        try {
                            # Try graceful stop first
                            $process.CloseMainWindow()
                            Start-Sleep -Seconds 2
                            
                            # Check if process is still running
                            $runningProcess = Get-Process -Id $processId -ErrorAction SilentlyContinue
                            if ($runningProcess) {
                                # Force kill if still running
                                Stop-Process -Id $processId -Force
                                Start-Sleep -Seconds 1
                            }
                            
                            Write-Development -Message "Stopped Laravel web server (PID: $processId)" -Type Success
                            $stoppedAny = $true
                            
                        } catch {
                            Write-Development -Message "Failed to stop process $processId`: $($_.Exception.Message)" -Type Error
                        }
                    } else {
                        Write-Development -Message "Process '$($process.Name)' (PID: $processId) on port $Port doesn't appear to be a Laravel web server" -Type Warning
                        Write-Development -Message "Use -Force to stop it anyway" -Type Info
                    }
                }
            }
        }
        
        # Verify port is now free
        Start-Sleep -Seconds 1
        if (-not (Test-DevPort -Port $Port)) {
            if ($stoppedAny) {
                Write-Development -Message "Laravel web server stopped successfully" -Type Success
            }
            return $true
        } else {
            Write-Development -Message "Laravel web port $Port is still in use after attempting to stop processes" -Type Warning
            return $false
        }
        
    } catch {
        Write-Development -Message "Failed to stop Laravel web server on port $Port`: $($_.Exception.Message)" -Type Error
        return $false
    }
}
}
Function Test-Laravel {
<#
    .SYNOPSIS
    Tests if the complete Laravel development environment is running
     
    .DESCRIPTION
    Checks if all Laravel development components are active: Web server, Vite, and Queue workers
     
    .PARAMETER Path
    The root directory of the Laravel application
     
    .PARAMETER WebPort
    Port for the Laravel web server (default: 8000)
     
    .PARAMETER VitePort
    Port for the Vite development server (default: 5173)
     
    .PARAMETER Queue
    Queue name for Laravel queue workers (optional - checks all if not specified)
     
    .EXAMPLE
    Test-Laravel
    Tests all Laravel services with default settings
     
    .EXAMPLE
    Test-Laravel -WebPort 8080 -VitePort 3000 -Queue "emails"
    Tests Laravel services with custom ports and specific queue
#>

[CmdletBinding()]
param(
    [Parameter()]
    [int]$WebPort = 8000,
    
    [Parameter()]
    [int]$VitePort = 5173,
    
    [Parameter()]
    [string]$Queue
)

Begin {
    Write-Development -Message "Testing Laravel Development Environment" -Type Header
    
    $webStatus = $false
    $viteStatus = $false
    $queueStatus = $false
    
    try {
        # Test Laravel Web Server
        Write-Development -Message "Testing Laravel web server..." -Type Info
        $webStatus = Test-LaravelWeb -Port $WebPort
        
        # Test Vite Development Server
        Write-Development -Message "Testing Vite development server..." -Type Info
        $viteStatus = Test-LaravelVite -Port $VitePort

        # Test Laravel Queue Worker
        Write-Development -Message "Testing Laravel queue worker..." -Type Info
        if ($Queue) {
            $queueStatus = Test-LaravelQueue -Queue $Queue
        } else {
            $queueStatus = Test-LaravelQueue
        }
        
        # Summary
        Write-Development -Message "" -Type Info
        Write-Development -Message "Laravel Development Environment Status:" -Type Info
        Write-Development -Message " - Web Server (port $WebPort): $(if($webStatus) { 'Running' } else { 'Stopped' })" -Type Info
        Write-Development -Message " - Vite Server (port $VitePort): $(if($viteStatus) { 'Running' } else { 'Stopped' })" -Type Info
        Write-Development -Message " - Queue Worker$(if($Queue) { " ($Queue)" }): $(if($queueStatus) { 'Running' } else { 'Stopped' })" -Type Info
        
        $allRunning = $webStatus -and $viteStatus -and $queueStatus
        
        if ($allRunning) {
            Write-Development -Message "All Laravel services are running!" -Type Success
        } else {
            $runningCount = @($webStatus, $viteStatus, $queueStatus) | Where-Object { $_ } | Measure-Object | Select-Object -ExpandProperty Count
            Write-Development -Message "$runningCount of 3 Laravel services are running" -Type Warning
        }
        
        return @{
            Web = $webStatus
            Vite = $viteStatus
            Queue = $queueStatus
            All = $allRunning
        }
        
    } catch {
        Write-Development -Message "Failed to test Laravel development environment: $($_.Exception.Message)" -Type Error
        return @{
            Web = $false
            Vite = $false
            Queue = $false
            All = $false
        }
    }
}
}
Function Test-LaravelQueue {
<#
    .SYNOPSIS
    Tests if the Laravel queue worker is running
     
    .DESCRIPTION
    Checks if Laravel queue worker processes are active
     
    .PARAMETER Path
    The root directory of the Laravel application
     
    .PARAMETER Queue
    Specific queue name to check (optional)
     
    .EXAMPLE
    Test-LaravelQueue
    Tests if any Laravel queue workers are running
     
    .EXAMPLE
    Test-LaravelQueue -Queue "emails"
    Tests if Laravel queue workers are running for the "emails" queue
#>

[CmdletBinding()]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWMICmdlet', '', Justification = 'Test file uses WMI for process detection')]
param(
    [Parameter()]
    [string]$Queue
)

Begin {
    Write-Development -Message "Testing Laravel queue worker$(if($Queue) { " for queue '$Queue'" })..." -Type Info
    
    try {
        # Find queue worker processes using WMI for more reliable command line detection
        # Note: Using WMI for compatibility with existing tests and broad system support
        $queueProcesses = Get-WmiObject Win32_Process | Where-Object {
            $_.Name -match "php" -and 
            $_.CommandLine -match "artisan.*queue:work"
        }
        
        if ($Queue) {
            $queueProcesses = $queueProcesses | Where-Object {
                $_.CommandLine -match "queue.*$Queue"
            }
        }
        
        if ($queueProcesses) {
            $processCount = $queueProcesses.Count
            Write-Development -Message "Found $processCount Laravel queue worker process$(if($processCount -gt 1) { 'es' })$(if($Queue) { " for queue '$Queue'" })" -Type Success
            
            foreach ($process in $queueProcesses) {
                Write-Development -Message " - PID: $($process.ProcessId), Started: $($process.CreationDate)" -Type Info
            }
            
            return $true
        } else {
            Write-Development -Message "No Laravel queue worker processes found$(if($Queue) { " for queue '$Queue'" })" -Type Info
            return $false
        }
        
    } catch {
        Write-Development -Message "Failed to test Laravel queue worker: $($_.Exception.Message)" -Type Error
        return $false
    }
}
}
Function Test-LaravelVite {
<#
    .SYNOPSIS
    Tests if the Laravel Vite development server is running
     
    .DESCRIPTION
    Checks if the Laravel Vite server is responding on the specified port
     
    .PARAMETER Port
    The port number to test (default: 5173)
     
    .EXAMPLE
    Test-LaravelVite -Port 5173
    Tests if Laravel Vite server is running on port 5173
#>

[CmdletBinding()]
param(
    [Parameter()]
    [int]$Port = 5173
)

Begin {
    Write-Development -Message "Testing Laravel Vite server on port $Port..." -Type Info
    
    if (Test-DevPort -Port $Port) {
        try {
            # Try to make a simple HTTP request to verify it's actually Vite
            $response = Invoke-WebRequest -Uri "http://127.0.0.1:$Port" -Method HEAD -TimeoutSec 5 -ErrorAction SilentlyContinue
            if ($response) {
                Write-Development -Message "Laravel Vite server is running and responding on port $Port" -Type Success
                return $true
            } else {
                Write-Development -Message "Port $Port is in use but not responding to HTTP requests" -Type Warning
                return $false
            }
        } catch {
            Write-Development -Message "Port $Port is in use but HTTP test failed: $($_.Exception.Message)" -Type Warning
            return $false
        }
    } else {
        Write-Development -Message "Laravel Vite server is not running on port $Port" -Type Info
        return $false
    }
}
}
Function Test-LaravelWeb {
<#
    .SYNOPSIS
    Tests if the Laravel web development server is running
     
    .DESCRIPTION
    Checks if the Laravel web server is responding on the specified port
     
    .PARAMETER Path
    The root directory of the Laravel application
     
    .PARAMETER Port
    The port number to test (default: 8000)
     
    .EXAMPLE
    Test-LaravelWeb -Port 8000
    Tests if Laravel web server is running on port 8000
#>

[CmdletBinding()]
param(
    [Parameter()]
    [int]$Port = 8000
)

Begin {
    Write-Development -Message "Testing Laravel web server on port $Port..." -Type Info
    
    if (Test-DevPort -Port $Port) {
        try {
            # Try to make a simple HTTP request to verify it's actually Laravel
            $response = Invoke-WebRequest -Uri "http://127.0.0.1:$Port" -Method HEAD -TimeoutSec 5 -ErrorAction SilentlyContinue
            if ($response) {
                Write-Development -Message "Laravel web server is running and responding on port $Port" -Type Success
                return $true
            } else {
                Write-Development -Message "Port $Port is in use but not responding to HTTP requests" -Type Warning
                return $false
            }
        } catch {
            Write-Development -Message "Port $Port is in use but HTTP test failed: $($_.Exception.Message)" -Type Warning
            return $false
        }
    } else {
        Write-Development -Message "Laravel web server is not running on port $Port" -Type Info
        return $false
    }
}
}