Functions/Ses/Sesio-Arc.ps1

# Import utilities
. $PSScriptRoot\..\Util.ps1

function Sesio-Arc {
    param (
        [Parameter(Position=0, Mandatory=$true)]
        [string]$Command,
        
        [Parameter(ValueFromRemainingArguments=$true)]
        $RemainingArgs
    )

    switch ($Command.ToLower()) {
        "create" {
            $params = @{}
            for ($i = 0; $i -lt $RemainingArgs.Count; $i += 2) {
                if ($i + 1 -lt $RemainingArgs.Count) {
                    $params[$RemainingArgs[$i].TrimStart('-')] = $RemainingArgs[$i + 1]
                }
            }
            Arc-Create @params
        }
        "update"{
            $params = @{}
            for ($i = 0; $i -lt $RemainingArgs.Count; $i++) {
                if ($RemainingArgs[$i] -eq '-o' -or $RemainingArgs[$i] -eq '-open') {
                    $params['OpenFile'] = 'notepad'
                    continue
                }
                if ($i + 1 -lt $RemainingArgs.Count) {
                    $params[$RemainingArgs[$i].TrimStart('-')] = $RemainingArgs[$i + 1]
                    $i++
                }
            }
            Arc-Update @params
        }
        "list" { Arc-List @RemainingArgs }
        "run" { 
            
            $params = @{}
            for ($i = 0; $i -lt $RemainingArgs.Count; $i += 2) {
                if ($i + 1 -lt $RemainingArgs.Count) {
                    $params[$RemainingArgs[$i].TrimStart('-')] = $RemainingArgs[$i + 1]
                }
            }
            Arc-Run @params 
        }
        "help" { Arc-Help }
        "open" {
            $params = @{}
            for ($i = 0; $i -lt $RemainingArgs.Count; $i += 2) {
                if ($i + 1 -lt $RemainingArgs.Count) {
                    $params[$RemainingArgs[$i].TrimStart('-')] = $RemainingArgs[$i + 1]
                }
            }
            Arc-Open @params
        }
        "delete" {
            $params = @{}
            for ($i = 0; $i -lt $RemainingArgs.Count; $i += 2) {
                if ($i + 1 -lt $RemainingArgs.Count) { $params[$RemainingArgs[$i].TrimStart('-')] = $RemainingArgs[$i + 1] }
            }
            Arc-Delete @params
        }
        default { Write-Host "Unknown command: $Command" }
    }
} 

function Arc-Run {
    param(
        [Parameter(Mandatory=$false)]
        [Alias("session")]
        [string]$SessionId,

        [Parameter(Mandatory=$false)]
        [Alias("type")]
        [string]$Types, 

        [Parameter(Mandatory=$false)]
        [Alias("env")]
        [string]$Environment,

        [Parameter(Mandatory=$false)]
        [Alias("aarc")]
        [string]$ArcFileName,

        [Parameter(Mandatory=$false)]
        [Alias("path")]
        [string]$FilePath,
        
        [Parameter(Mandatory=$false)]
        [Alias("global")]
        [switch]$GlobalTemplate
    )

    if($GlobalTemplate) {
        if(-not $ArcFileName) {
            $ArcFileName = Read-Host "Enter the name of arc file"
        }
    
        if(-not $Environment) {
            $Environment = Read-Host "Enter the environment name (Default: dev)"
            if(-not $Environment) {
              $Environment = "dev"
            }
        }
       # Get the .aarc file
        $sesioFolder = Join-Path $env:USERPROFILE ".sesio"
        $aarcFileName = "$Environment.$ArcFileName.aarc"
        $aarcFilePath = Join-Path $sesioFolder $aarcFileName
    }
    else {
        $aarcFilePath = Join-Path (Get-Location) ".sesio/default.aarc"
    }

    if(-not $SessionId) {
         $SessionId = Read-Host "Provide Session Name (Default: AutoSession)"
         if(-not $SessionId) {
            $SessionId = "AutoSession"
         }
    }

    if(-not $Types) {
        $Types = "pdf|csv|doc|docx|xls|xlsx|txt"
    }



    # Read URL from .env file in .sesio folder
    $sesioFolder = Join-Path $env:USERPROFILE ".sesio"
    $envFile = Join-Path $sesioFolder ".env"
    
    # Create .sesio folder if it doesn't exist
    if (-not (Test-Path $sesioFolder)) {
        New-Item -ItemType Directory -Path $sesioFolder -Force | Out-Null
    }

    $url = $null
    if (Test-Path $envFile) {
        Get-Content $envFile | ForEach-Object {
            if ($_ -match "^url=(.*)$") {
                $url = $matches[1]
            }
        }
    }

    if (-not $url) {
        
        Write-Warning "URL not found in .env file."
        $url = Read-Host "Please enter the URL"
        
        if (-not $url) {
            Write-Error "URL is required to continue."
            return
        }

        # Create or update .env file with the URL
        if (Test-Path $envFile) {
            $envContent = Get-Content $envFile | Where-Object { !$_.StartsWith("url=") }
            $envContent += "url=$url"
            $envContent | Set-Content $envFile
        } else {
            "url=$url" | Set-Content $envFile
        }
        Write-Info "URL has been saved to .env file"
    }

    $UploadUrl = "$url/api/upload/documents/cli"

    # Modify the directory selection logic
    $currentDirectory = if ($FilePath) {
        Resolve-Path $FilePath -ErrorAction SilentlyContinue
        if (-not $?) {
            Write-Error "Invalid path specified"
            return
        }
        $FilePath
    } else {
        Get-Location
    }

    # Modify the file search logic to prevent duplicates
    $files = Get-ChildItem -Path $currentDirectory -File | 
        Where-Object { $_.Extension -match "\.($Types)$" } |
        Select-Object -Unique FullName, Name # Only select unique files based on full path

    if ($files.Count -eq 0) {
        Write-Host "No matching files found in the specified directory."
        return
    }

    Write-Host "Found $($files.Count) files to process.`n"

  
    if (-not (Test-Path $aarcFilePath)) {
        Write-Warning ".aarc file not found: $aarcFilePath"
    }

    # Create arrays to store results and overflow messages
    $results = @()
    $overflowMessages = @()

    # Initialize results array with all files showing "Queued" status
    foreach ($file in $files) {
        $results += [PSCustomObject]@{
            FileName = $file.Name.PadRight(30).Substring(0,30)
            Status = "⏳ Queued".PadRight(15).Substring(0,15)
            Time = "--".PadRight(10).Substring(0,10)
            Message = $(if ("Waiting to process".Length -gt 30) {
                "Waiting to process".Substring(0,27) + "..."
            } else {
                "Waiting to process".PadRight(30)
            })
        }
    }

    # Function to display results and overflow messages
    function Show-Results {
        Clear-Host
        Write-Host "Found $($files.Count) files to process.`n"
        Write-Host "Upload Results:"
        Write-Host "----------------------------------------"
        $results | Format-Table -AutoSize -Wrap

        if ($overflowMessages.Count -gt 0) {
            Write-Host "`nDetailed Messages:"
            Write-Host "----------------------------------------"
            foreach ($msg in $overflowMessages) {
                Write-Host "[$($msg.Index)] $($msg.FileName):"
                Write-Host " $($msg.FullMessage)`n"
            }
        }
    }

    # Process each file
    for ($i = 0; $i -lt $files.Count; $i++) {
        $file = $files[$i]
        $FileStream = $null
        $aarcFileStream = $null
        $multipartContent = $null
        
        try {
            # Update status to uploading for current file
            $results[$i].Status = "🔄 Uploading..."
            $results[$i].Message = "In progress"
            
            # Refresh display
            Clear-Host
            Write-Host "Found $($files.Count) files to process.`n"
            Write-Host "Upload Results:"
            Write-Host "----------------------------------------"
            $results | Format-Table -AutoSize -Wrap

            $headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
            $headers.Add("sess-id", 'sid-'+$SessionId)

            $multipartContent = [System.Net.Http.MultipartFormDataContent]::new()

            # Add the main file
            $FileStream = [System.IO.FileStream]::new($file.FullName, [System.IO.FileMode]::Open)
            $fileHeader = [System.Net.Http.Headers.ContentDispositionHeaderValue]::new("form-data")
            $fileHeader.Name = "file"
            $fileHeader.FileName = $file.Name
            $fileContent = [System.Net.Http.StreamContent]::new($FileStream)
            $fileContent.Headers.ContentDisposition = $fileHeader
            $multipartContent.Add($fileContent)

            # Add the .aarc file if it exists
            if (Test-Path $aarcFilePath) {
                $aarcFileStream = [System.IO.FileStream]::new($aarcFilePath, [System.IO.FileMode]::Open)
                $aarcFileHeader = [System.Net.Http.Headers.ContentDispositionHeaderValue]::new("form-data")
                $aarcFileHeader.Name = "aarc"
                $aarcFileHeader.FileName = $aarcFileName
                $aarcFileContent = [System.Net.Http.StreamContent]::new($aarcFileStream)
                $aarcFileContent.Headers.ContentDisposition = $aarcFileHeader
                $multipartContent.Add($aarcFileContent)
            }

            $timer = [System.Diagnostics.Stopwatch]::StartNew()
            $response = Invoke-RestMethod -Uri $UploadUrl -Method Post -Headers $headers -Body $multipartContent

            $timer.Stop()
            $uploadTime = "{0:N2}" -f $timer.Elapsed.TotalSeconds

            # Update result for this file
            $results[$i].Status = "✅ Success".PadRight(15).Substring(0,15)
            $results[$i].Time = "$uploadTime sec".PadRight(10).Substring(0,10)
            
            if ($response.message.Length -gt 30) {
                $results[$i].Message = $response.message.Substring(0,27) + "..."
                $overflowMessages += @{
                    Index = $i + 1
                    FileName = $files[$i].Name
                    FullMessage = $response.message
                }
            } else {
                $results[$i].Message = $response.message.PadRight(30)
            }
        }
        catch {
            # Update error result for this file
            $results[$i].Status = "❌ Failed".PadRight(15).Substring(0,15)
            $results[$i].Time = "N/A".PadRight(10).Substring(0,10)
            
            if ($_.Exception.Message.Length -gt 30) {
                $results[$i].Message = $_.Exception.Message.Substring(0,27) + "..."
                $overflowMessages += @{
                    Index = $i + 1
                    FileName = $files[$i].Name
                    FullMessage = $_.Exception.Message
                }
            } else {
                $results[$i].Message = $_.Exception.Message.PadRight(30)
            }
        }
        finally {
            if ($FileStream) { $FileStream.Dispose() }
            if ($aarcFileStream) { $aarcFileStream.Dispose() }
            if ($multipartContent) { $multipartContent.Dispose() }

            # Show updated results
            Show-Results
        }
    }
}

function Arc-Update {
    param(
        [Parameter(Mandatory=$false)]
        [Alias("file")]
        [string]$FileName,
        
        [Parameter(Mandatory=$false)]
        [Alias("env")]
        [string]$Environment,

        [Parameter(Mandatory=$false)]
        [Alias("open")]
        [string]$OpenFile
    )
    
  if (-not $FileName) {   
        $FileName = Read-Host "Enter the file name"
    }

    if (-not $Environment) {
        $Environment = Read-Host "Enter the environment name"
    }
    if (-not $OpenFile) {
        $OpenFile = Read-Host "Enter the open command (code or notepad). press Enter to use notepad."
    }

    if (-not $FileName -or -not $Environment) {
        Write-Host "File name and environment are required"
        return
    }   
    
    $sesioFolder = Join-Path $env:USERPROFILE ".sesio"
    $arcFileName = "$Environment.$FileName.aarc"
    $arcFilePath = Join-Path $sesioFolder $arcFileName

    if (-not (Test-Path $arcFilePath)) {
        Write-Warning "File not found: $arcFilePath"
        return
    }
    switch ($OpenFile) {
        'code' { code $arcFilePath }
        default { notepad $arcFilePath }
    }
    return
}

# Update messages in Arc-Create
function Arc-Create {
    param(
        [Parameter(Mandatory=$false)]
        [Alias("name")]
        [string]$FileName,
        
        [Parameter(Mandatory=$false)]
        [Alias("env")]
        [string]$Environment
    )

    # Create .sesio folder if it doesn't exist
    $sesioFolder = Join-Path $env:USERPROFILE ".sesio"
    if (-not (Test-Path $sesioFolder)) {
        New-Item -ItemType Directory -Path $sesioFolder -Force | Out-Null
        Write-Host "Created .sesio folder: $sesioFolder"
    } 
    
    if (-not $FileName) {   
        $FileName = Read-Host "Enter the file name (required)"
        if (-not $FileName) {
            Write-Error "Cannot create arc file without file name"
            return
        }   
    }

    if (-not $Environment) {
        $Environment = Read-Host "Enter the environment name (Default: dev)"
        if(-not $Environment) {
            $Environment = "dev"
        }
    }
  
    # Create arc file
    $arcFileName = "$Environment.$FileName.aarc"
    $arcFilePath = Join-Path $sesioFolder $arcFileName
    if (Test-Path $arcFilePath) {
        Write-Warning "Arc file with the name $arcFileName already exists. Please enter a different file name."
        Write-Info " Use 'sesio arc list' to see all arc files."
        Write-Host ""
        return
    }
    else{
        $templateFilePath = Join-Path $sesioFolder "template.aarc"
        if (-not (Test-Path $templateFilePath)) {
            Write-Error "Template file not found: $templateFilePath"
            return
        }
        Copy-Item -Path $templateFilePath -Destination $arcFilePath -Force
        Write-Info "Arc file created successfully: $arcFilePath"
        Arc-Update -FileName $FileName -Environment $Environment -OpenFile "notepad"

    }

}

# Update messages in Arc-Delete
function Arc-Delete {
    param(
        [Parameter(Mandatory=$true)]
        [Alias("name")]
        [string]$FileName,

        [Parameter(Mandatory=$false)]
        [Alias("env")]
        [string]$Environment
    )

    if (-not $FileName) {
        $FileName = Read-Host "Enter the file name (required)"
        if (-not $FileName) {
            Write-Host "Cannot delete arc file without file name"
            return
        }
    }

    if (-not $Environment) {
        $Environment = Read-Host "Enter the environment name (Default: dev)"
        if (-not $Environment) {
            $Environment = "dev"
        }
    }

    $arcFileName = "$Environment.$FileName.aarc"
    $arcFilePath = Join-Path $sesioFolder $arcFileName
    if (-not (Test-Path $arcFilePath)) {
        Write-Warning "Arc file with the name $arcFileName does not exist."
        return
    } else {
        Remove-Item -Path $arcFilePath -Force | Out-Null
        Write-Info "Arc file deleted successfully: $arcFilePath"
    }
}

# Update messages in Arc-List
function Arc-List {
    param(
        [Alias("e")][string]$Environment
    )
    $sesioFolder = Join-Path $env:USERPROFILE ".sesio"
   
    if (-not (Test-Path $sesioFolder)) {
        Write-Warning "No .sesio folder found at $sesioFolder. No arc files to list."
        return
    }

    if(-not $Environment) {
        $arcFiles = Get-ChildItem -Path $sesioFolder -Filter "*.aarc" | Where-Object {$_.Name -ne "template.aarc"}
    }
    else {
        $arcFiles = Get-ChildItem -Path $sesioFolder -Filter "$Environment.*.aarc" | Where-Object {$_.Name -ne "template.aarc"}
    }

    if ($arcFiles.Count -eq 0) {
        Write-Warning "No .aarc files found in the .sesio folder."
    } else {
        Write-Host ""
        Write-Info "Found $($arcFiles.Count) .aarc files."
        $groupedFiles = $arcFiles | Group-Object { ($_.BaseName -split '\.')[0] }
        
        $table = @()
        foreach ($group in $groupedFiles) {
            foreach ($file in $group.Group) {
                $fileName = $file.BaseName -split '\.' | Select-Object -Index 1
                $fileSize = if ($file.Length -lt 1KB) {"$($file.Length) B"} elseif ($file.Length -lt 1MB) {"{0:N2} KB" -f ($file.Length / 1KB)} else {"{0:N2} MB" -f ($file.Length / 1MB)}
                $table += [PSCustomObject]@{
                    Environment = $group.Name.PadRight(15).Substring(0,15)
                    FileName = $fileName.PadRight(30).Substring(0,30)
                    FileSize = $fileSize.PadRight(10).Substring(0,10)
                }
            }
        }
        $table | Format-Table -AutoSize -Wrap
    }
}

function Arc-Help {
    Write-Host "$([char]0x1b)[32mSesio Arc Help$([char]0x1b)[0m"
    Write-Host ""
    Write-Host "$([char]0x1b)[32mUsage:$([char]0x1b)[0m Sesio arc <command> [options]"
    Write-Host ""
    Write-Host "$([char]0x1b)[32mCommands:$([char]0x1b)[0m"
    Write-Host "$([char]0x1b)[32m--------------------------------$([char]0x1b)[0m"
    Write-Host "$([char]0x1b)[31mcreate$([char]0x1b)[0m - Create a new arc file"
    Write-Host " Options:"
    Write-Host " -file File name for the arc file"
    Write-Host " -env Environment name (dev, prod, etc.)"
    Write-Host "Example: "
    Write-Host " sesio arc create -file config -env dev"
    Write-Host ""
    Write-Host "$([char]0x1b)[31mupdate$([char]0x1b)[0m - Update existing arc file"
    Write-Host " Options:"
    Write-Host " -file File name to update"
    Write-Host " -env Environment name"
    Write-Host " -open Editor to open file (code or notepad)"
    Write-Host "Example:"
    Write-Host " sesio arc update -file config -env dev -open code"
    Write-Host ""
    Write-Host "$([char]0x1b)[31mlist$([char]0x1b)[0m - List all arc files"
    Write-Host " Options:"
    Write-Host " -e Filter by environment"
    Write-Host ""
    Write-Host "Example:"
    Write-Host " sesio arc list -e dev"
    Write-Host ""
    Write-Host "$([char]0x1b)[31mdelete$([char]0x1b)[0m - Delete an arc file"
    Write-Host " Options:"
    Write-Host " -name File name to delete"
    Write-Host " -env Environment name"
    Write-Host ""
    Write-Host "Example:"
    Write-Host " sesio arc delete -name config -env dev"
    Write-Host ""
    Write-Host "$([char]0x1b)[31mrun$([char]0x1b)[0m - Run a session"
    Write-Host " Options:"
    Write-Host " -session Session ID for the upload"
    Write-Host " -type File types to process (default: pdf|csv|doc|docx|xls|xlsx|txt)"
    Write-Host " -env Environment name"
    Write-Host " -aarc Arc file name"
    Write-Host " -path Path to the directory containing files"
    Write-Host ""
    Write-Host "Example:"
    Write-Host " sesio arc run -session test -type 'pdf|csv' -env dev -aarc config"
    Write-Host ""
    Write-Host "$([char]0x1b)[31mopen$([char]0x1b)[0m - Show content of arc file in console"
    Write-Host " Options:"
    Write-Host " -file File name to open"
    Write-Host " -env Environment name"
    Write-Host ""
    Write-Host "Example:"
    Write-Host " sesio arc open -file config -env dev"
    Write-Host ""
    Write-Host "$([char]0x1b)[31mhelp$([char]0x1b)[0m - Show this help message"
    Write-Host "$([char]0x1b)[32m--------------------------------$([char]0x1b)[0m"
    Write-Host ""
   
}

# Add new function for opening arc files
function Arc-Open {
    param(
        [Parameter(Mandatory=$false)]
        [Alias("file")]
        [string]$FileName,
        
        [Parameter(Mandatory=$false)]
        [Alias("env")]
        [string]$Environment
    )

    if (-not $FileName) {   
        $FileName = Read-Host "Enter the file name"
    }

    if (-not $Environment) {
        $Environment = Read-Host "Enter the environment name"
    }

    if (-not $FileName -or -not $Environment) {
        Write-Host "File name and environment are required"
        return
    }   
    
    $sesioFolder = Join-Path $env:USERPROFILE ".sesio"
    $arcFileName = "$Environment.$FileName.aarc"
    $arcFilePath = Join-Path $sesioFolder $arcFileName

    if (-not (Test-Path $arcFilePath)) {
        Write-Warning "File not found: $arcFilePath"
        return
    }

    Write-Host "`n$([char]0x1b)[32mContent of $($arcFileName):$([char]0x1b)[0m"
    Write-Host "$([char]0x1b)[32m--------------------------------$([char]0x1b)[0m"
    Get-Content $arcFilePath
    Write-Host "$([char]0x1b)[32m--------------------------------$([char]0x1b)[0m"
}


Export-ModuleMember -Function Sesio-Arc