Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing

$ErrorActionPreference = 'Stop'
$SuiteRoot = Split-Path -Parent $MyInvocation.MyCommand.Path
$CatalogPath = Join-Path $SuiteRoot 'suite-catalog.json'

function Show-Error([string]$message) {
    [System.Windows.Forms.MessageBox]::Show($message, 'Portfolio Suite Launcher', 'OK', 'Error') | Out-Null
}

if (-not (Test-Path -LiteralPath $CatalogPath)) {
    Show-Error 'suite-catalog.json tidak ditemukan.'
    exit 1
}

function Get-Catalog {
    try {
        $raw = Get-Content -LiteralPath $CatalogPath -Raw -Encoding UTF8
        $items = $raw | ConvertFrom-Json
        if ($null -eq $items) { return @() }
        if ($items -is [System.Array]) { return $items }
        return @($items)
    }
    catch {
        Show-Error ("Gagal membaca catalog:`r`n" + $_.Exception.Message)
        return @()
    }
}

$form = New-Object System.Windows.Forms.Form
$form.Text = 'Portfolio Suite Launcher (Standalone PowerShell)'
$form.StartPosition = 'CenterScreen'
$form.Size = New-Object System.Drawing.Size(1380, 840)
$form.MinimumSize = New-Object System.Drawing.Size(1220, 720)
$form.Font = New-Object System.Drawing.Font('Segoe UI', 10)

$split = New-Object System.Windows.Forms.SplitContainer
$split.Dock = 'Fill'
$split.SplitterDistance = 760
$form.Controls.Add($split)

$leftTitle = New-Object System.Windows.Forms.Label
$leftTitle.Text = 'Daftar Proyek'
$leftTitle.Dock = 'Top'
$leftTitle.Height = 34
$leftTitle.Font = New-Object System.Drawing.Font('Segoe UI Semibold', 14)
$split.Panel1.Controls.Add($leftTitle)

$list = New-Object System.Windows.Forms.ListBox
$list.Dock = 'Fill'
$list.DisplayMember = 'name'
$split.Panel1.Controls.Add($list)
$list.BringToFront()

$panel = New-Object System.Windows.Forms.TableLayoutPanel
$panel.Dock = 'Fill'
$panel.RowCount = 5
$panel.ColumnCount = 1
$panel.RowStyles.Add((New-Object System.Windows.Forms.RowStyle([System.Windows.Forms.SizeType]::AutoSize)))
$panel.RowStyles.Add((New-Object System.Windows.Forms.RowStyle([System.Windows.Forms.SizeType]::AutoSize)))
$panel.RowStyles.Add((New-Object System.Windows.Forms.RowStyle([System.Windows.Forms.SizeType]::AutoSize)))
$panel.RowStyles.Add((New-Object System.Windows.Forms.RowStyle([System.Windows.Forms.SizeType]::AutoSize)))
$panel.RowStyles.Add((New-Object System.Windows.Forms.RowStyle([System.Windows.Forms.SizeType]::Percent, 100)))
$split.Panel2.Controls.Add($panel)

$lblTitle = New-Object System.Windows.Forms.Label
$lblTitle.Text = 'Pilih proyek'
$lblTitle.Font = New-Object System.Drawing.Font('Segoe UI Semibold', 18)
$lblTitle.AutoSize = $true
$panel.Controls.Add($lblTitle, 0, 0)

$lblStack = New-Object System.Windows.Forms.Label
$lblStack.AutoSize = $true
$lblStack.ForeColor = [System.Drawing.Color]::FromArgb(30, 64, 175)
$lblStack.Font = New-Object System.Drawing.Font('Segoe UI', 10, [System.Drawing.FontStyle]::Bold)
$lblStack.Text = 'Stack: -'
$panel.Controls.Add($lblStack, 0, 1)

$txtSummary = New-Object System.Windows.Forms.TextBox
$txtSummary.Multiline = $true
$txtSummary.ReadOnly = $true
$txtSummary.Height = 88
$txtSummary.Dock = 'Top'
$txtSummary.Text = 'Pilih proyek di sebelah kiri.'
$panel.Controls.Add($txtSummary, 0, 2)

$txtCommand = New-Object System.Windows.Forms.TextBox
$txtCommand.ReadOnly = $true
$txtCommand.Dock = 'Top'
$txtCommand.Text = 'Perintah utama: -'
$panel.Controls.Add($txtCommand, 0, 3)

$bottom = New-Object System.Windows.Forms.TableLayoutPanel
$bottom.Dock = 'Fill'
$bottom.RowCount = 3
$bottom.ColumnCount = 1
$bottom.RowStyles.Add((New-Object System.Windows.Forms.RowStyle([System.Windows.Forms.SizeType]::AutoSize)))
$bottom.RowStyles.Add((New-Object System.Windows.Forms.RowStyle([System.Windows.Forms.SizeType]::AutoSize)))
$bottom.RowStyles.Add((New-Object System.Windows.Forms.RowStyle([System.Windows.Forms.SizeType]::Percent, 100)))
$panel.Controls.Add($bottom, 0, 4)

$buttons = New-Object System.Windows.Forms.FlowLayoutPanel
$buttons.Dock = 'Top'
$buttons.AutoSize = $true
$bottom.Controls.Add($buttons, 0, 0)

$status = New-Object System.Windows.Forms.Label
$status.Text = 'Status: Siap'
$status.AutoSize = $true
$status.Font = New-Object System.Drawing.Font('Segoe UI', 10, [System.Drawing.FontStyle]::Bold)
$bottom.Controls.Add($status, 0, 1)

$output = New-Object System.Windows.Forms.RichTextBox
$output.Dock = 'Fill'
$output.ReadOnly = $true
$output.Font = New-Object System.Drawing.Font('Consolas', 10)
$output.Text = 'Output demo akan tampil di sini...'
$bottom.Controls.Add($output, 0, 2)

function Load-List {
    $list.Items.Clear()
    foreach ($p in (Get-Catalog)) {
        [void]$list.Items.Add($p)
    }
    if ($list.Items.Count -gt 0) {
        $list.SelectedIndex = 0
    }
}

function Get-SelectedProject {
    if ($null -eq $list.SelectedItem) { return $null }
    return $list.SelectedItem
}

function Get-ProjectPath($item) {
    if ($null -eq $item) { return $SuiteRoot }
    $folder = [string]$item.folder
    if ([string]::IsNullOrWhiteSpace($folder)) { return $SuiteRoot }
    $normalized = $folder.Replace('/', [IO.Path]::DirectorySeparatorChar)
    return [IO.Path]::GetFullPath((Join-Path $SuiteRoot $normalized))
}

function Append-Output([string]$text) {
    $output.AppendText($text)
    $output.SelectionStart = $output.TextLength
    $output.ScrollToCaret()
}

function Update-Details {
    $item = Get-SelectedProject
    if ($null -eq $item) { return }

    $name = [string]$item.name
    $stack = [string]$item.stack
    $summary = [string]$item.summary
    $folder = [string]$item.folder
    $runHint = [string]$item.runHint

    $lblTitle.Text = if ([string]::IsNullOrWhiteSpace($name)) { '(Tanpa nama)' } else { $name }
    $lblStack.Text = 'Stack: ' + ($(if ([string]::IsNullOrWhiteSpace($stack)) { '-' } else { $stack }))
    $txtSummary.Text = $summary + [Environment]::NewLine + [Environment]::NewLine + 'Folder: ' + $folder
    $txtCommand.Text = 'Perintah utama: ' + $runHint
    $output.Text = 'Siap menjalankan demo untuk ' + $lblTitle.Text + '.' + [Environment]::NewLine + "Klik 'Jalankan Demo' untuk melihat output proses di sini."
    $status.Text = 'Status: Siap'
}

function Invoke-ProjectScript([string]$scriptName, [bool]$captureOutput) {
    try {
        $item = Get-SelectedProject
        if ($null -eq $item) { return }

        $projectPath = Get-ProjectPath $item
        $scriptPath = Join-Path $projectPath $scriptName

        if (-not (Test-Path -LiteralPath $scriptPath)) {
            $output.Text = 'Script tidak ditemukan: ' + $scriptPath
            $status.Text = 'Status: Script tidak ditemukan'
            return
        }

        $psExe = (Get-Command powershell.exe -ErrorAction SilentlyContinue).Source
        if (-not $psExe) { $psExe = (Get-Command pwsh.exe -ErrorAction SilentlyContinue).Source }
        if (-not $psExe) { throw 'PowerShell executable tidak ditemukan.' }

        if ($captureOutput) {
            $output.Clear()
            Append-Output("Menjalankan $($lblTitle.Text)...`r`n")
            $status.Text = 'Status: Berjalan'

            $psi = New-Object System.Diagnostics.ProcessStartInfo
            $psi.FileName = $psExe
            $psi.WorkingDirectory = $projectPath
            $psi.UseShellExecute = $false
            $psi.RedirectStandardOutput = $true
            $psi.RedirectStandardError = $true
            $psi.CreateNoWindow = $true
            $psi.Arguments = '-NoProfile -ExecutionPolicy Bypass -File "' + $scriptPath + '"'

            $proc = New-Object System.Diagnostics.Process
            $proc.StartInfo = $psi
            [void]$proc.Start()
            $stdout = $proc.StandardOutput.ReadToEnd()
            $stderr = $proc.StandardError.ReadToEnd()
            $proc.WaitForExit()

            if ($stdout) { Append-Output($stdout.TrimEnd() + [Environment]::NewLine) }
            if ($stderr) { Append-Output('[ERR] ' + $stderr.TrimEnd() + [Environment]::NewLine) }

            if ($proc.ExitCode -eq 0) {
                $status.Text = 'Status: Selesai'
            }
            else {
                $status.Text = 'Status: Selesai dengan kode ' + $proc.ExitCode
            }
        }
        else {
            Start-Process -FilePath $psExe -WorkingDirectory $projectPath -ArgumentList @('-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', $scriptPath) | Out-Null
            $status.Text = 'Status: Aplikasi dibuka di proses terpisah'
            Append-Output([Environment]::NewLine + 'Aplikasi dibuka.' + [Environment]::NewLine)
        }
    }
    catch {
        $status.Text = 'Status: Gagal'
        Append-Output('[ERR] ' + $_.Exception.Message + [Environment]::NewLine)
    }
}

$btnDemo = New-Object System.Windows.Forms.Button
$btnDemo.Text = 'Jalankan Demo'
$btnDemo.AutoSize = $true
$btnDemo.Add_Click({ Invoke-ProjectScript 'demo.ps1' $true })
$buttons.Controls.Add($btnDemo)

$btnOpen = New-Object System.Windows.Forms.Button
$btnOpen.Text = 'Buka Aplikasi'
$btnOpen.AutoSize = $true
$btnOpen.Add_Click({ Invoke-ProjectScript 'open.ps1' $false })
$buttons.Controls.Add($btnOpen)

$btnFolder = New-Object System.Windows.Forms.Button
$btnFolder.Text = 'Buka Folder'
$btnFolder.AutoSize = $true
$btnFolder.Add_Click({
    try {
        $item = Get-SelectedProject
        if ($null -ne $item) {
            Start-Process explorer.exe (Get-ProjectPath $item)
        }
    }
    catch {
        $status.Text = 'Status: Gagal membuka folder'
        Append-Output('[ERR] ' + $_.Exception.Message + [Environment]::NewLine)
    }
})
$buttons.Controls.Add($btnFolder)

$btnCopy = New-Object System.Windows.Forms.Button
$btnCopy.Text = 'Salin Perintah'
$btnCopy.AutoSize = $true
$btnCopy.Add_Click({
    try {
        $item = Get-SelectedProject
        if ($null -ne $item) {
            [System.Windows.Forms.Clipboard]::SetText([string]$item.runHint)
            $status.Text = 'Status: Perintah disalin ke clipboard'
        }
    }
    catch {
        $status.Text = 'Status: Gagal menyalin'
        Append-Output('[ERR] ' + $_.Exception.Message + [Environment]::NewLine)
    }
})
$buttons.Controls.Add($btnCopy)

$btnReload = New-Object System.Windows.Forms.Button
$btnReload.Text = 'Muat Ulang'
$btnReload.AutoSize = $true
$btnReload.Add_Click({
    Load-List
    $status.Text = 'Status: Catalog dimuat ulang'
})
$buttons.Controls.Add($btnReload)

$list.Add_SelectedIndexChanged({ Update-Details })
Load-List

[void]$form.ShowDialog()
