# YarMenu POS - graphical setup wizard (VC++ + copy + register)
# Usage: powershell -STA -WindowStyle Hidden -ExecutionPolicy Bypass -File setup_gui.ps1

param(
    [string]$SourceDir = $PSScriptRoot
)

if ([Threading.Thread]::CurrentThread.ApartmentState -ne 'STA') {
    $argsList = @(
        '-NoProfile', '-NoLogo', '-STA', '-WindowStyle', 'Hidden',
        '-ExecutionPolicy', 'Bypass', '-File', $PSCommandPath
    )
    if ($SourceDir -ne $PSScriptRoot) { $argsList += @('-SourceDir', $SourceDir) }
    & powershell.exe @argsList
    exit $LASTEXITCODE
}

$ErrorActionPreference = 'Stop'

try {
    Add-Type @'
using System;
using System.Runtime.InteropServices;
public static class YarMenuSetupNative {
  [DllImport("kernel32.dll")] public static extern IntPtr GetConsoleWindow();
  [DllImport("user32.dll")] public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
  [DllImport("shcore.dll")] public static extern int SetProcessDpiAwareness(int awareness);
  [DllImport("user32.dll")] public static extern bool SetProcessDPIAware();
  [DllImport("shell32.dll")] public static extern int SetCurrentProcessExplicitAppUserModelID([MarshalAs(UnmanagedType.LPWStr)] string AppId);
}
'@
    $console = [YarMenuSetupNative]::GetConsoleWindow()
    if ($console -ne [IntPtr]::Zero) {
        [void][YarMenuSetupNative]::ShowWindow($console, 0)
    }
    try { [void][YarMenuSetupNative]::SetProcessDpiAwareness(2) } catch {
        [void][YarMenuSetupNative]::SetProcessDPIAware()
    }
    try { [void][YarMenuSetupNative]::SetCurrentProcessExplicitAppUserModelID('YarMenu.POS.Setup.1.0') } catch {}
} catch {}

Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
[System.Windows.Forms.Application]::EnableVisualStyles()
[System.Windows.Forms.Application]::SetCompatibleTextRenderingDefault($false)

function Resolve-InstallSourceDir {
    param([string]$Dir)
    if ([string]::IsNullOrWhiteSpace($Dir)) { $Dir = $PSScriptRoot }
    $Dir = $Dir.Trim().Trim('"').TrimEnd('\')
    if (-not (Test-Path -LiteralPath $Dir)) { throw "Install folder not found: $Dir" }
    return (Get-Item -LiteralPath $Dir).FullName
}

function New-UiSize([int]$w, [int]$h) { return [System.Drawing.Size]::new($w, $h) }
function New-UiPoint([int]$x, [int]$y) { return [System.Drawing.Point]::new($x, $y) }
function New-UiFont {
    param(
        [string]$Family,
        [float]$Size,
        [System.Drawing.FontStyle]$Style = [System.Drawing.FontStyle]::Regular
    )
    return [System.Drawing.Font]::new($Family, $Size, $Style, [System.Drawing.GraphicsUnit]::Point)
}

function New-HighQualityBitmap {
    param(
        [System.Drawing.Image]$Source,
        [int]$Width,
        [int]$Height
    )
    $bmp = [System.Drawing.Bitmap]::new($Width, $Height)
    $g = [System.Drawing.Graphics]::FromImage($bmp)
    $g.InterpolationMode = [System.Drawing.Drawing2D.InterpolationMode]::HighQualityBicubic
    $g.SmoothingMode = [System.Drawing.Drawing2D.SmoothingMode]::HighQuality
    $g.PixelOffsetMode = [System.Drawing.Drawing2D.PixelOffsetMode]::HighQuality
    $g.CompositingQuality = [System.Drawing.Drawing2D.CompositingQuality]::HighQuality
    $g.Clear([System.Drawing.Color]::Transparent)
    $g.DrawImage($Source, 0, 0, $Width, $Height)
    $g.Dispose()
    return $bmp
}

function New-RoundedBitmap {
    param(
        [System.Drawing.Image]$Source,
        [int]$Size,
        [int]$Radius
    )
    $scaled = New-HighQualityBitmap -Source $Source -Width $Size -Height $Size
    $result = [System.Drawing.Bitmap]::new($Size, $Size)
    $g = [System.Drawing.Graphics]::FromImage($result)
    $g.SmoothingMode = [System.Drawing.Drawing2D.SmoothingMode]::AntiAlias
    $path = New-Object System.Drawing.Drawing2D.GraphicsPath
    $d = $Radius * 2
    $path.AddArc(0, 0, $d, $d, 180, 90)
    $path.AddArc($Size - $d, 0, $d, $d, 270, 90)
    $path.AddArc($Size - $d, $Size - $d, $d, $d, 0, 90)
    $path.AddArc(0, $Size - $d, $d, $d, 90, 90)
    $path.CloseFigure()
    $g.SetClip($path)
    $g.DrawImage($scaled, 0, 0, $Size, $Size)
    $g.Dispose()
    $path.Dispose()
    $scaled.Dispose()
    return $result
}

function Get-YarMenuBrandAssets {
    param([string]$Dir)
    $logoSize = 72
    $radius = 16

    $pngPath = Join-Path $Dir 'setup_logo.png'
    $icoPath = Join-Path $Dir 'setup.ico'
    $exePath = Join-Path $Dir 'yarmenu_pos.exe'

    $windowIcon = $null
    if (Test-Path -LiteralPath $icoPath) {
        $windowIcon = [System.Drawing.Icon]::new($icoPath)
    } elseif (Test-Path -LiteralPath $exePath) {
        $windowIcon = [System.Drawing.Icon]::ExtractAssociatedIcon($exePath)
    } else {
        $windowIcon = [System.Drawing.SystemIcons]::Application
    }

    $source = $null
    if (Test-Path -LiteralPath $pngPath) {
        $source = [System.Drawing.Image]::FromFile($pngPath)
    } elseif ($null -ne $windowIcon) {
        $source = $windowIcon.ToBitmap()
    }

    if ($null -eq $source) {
        $fallback = [System.Drawing.SystemIcons]::Application.ToBitmap()
        return @{
            Logo = $fallback
            Icon = [System.Drawing.SystemIcons]::Application
        }
    }

    $logo = New-RoundedBitmap -Source $source -Size $logoSize -Radius $radius
    $source.Dispose()

    return @{ Logo = $logo; Icon = $windowIcon }
}

function Stop-YarMenuProcesses {
    $procs = Get-Process -Name 'yarmenu_pos' -ErrorAction SilentlyContinue
    foreach ($proc in @($procs)) {
        try {
            if ($proc.MainWindowHandle -ne 0) { $proc.CloseMainWindow() | Out-Null }
        } catch {}
    }
    Start-Sleep -Milliseconds 800
    $procs = Get-Process -Name 'yarmenu_pos' -ErrorAction SilentlyContinue
    foreach ($proc in @($procs)) {
        Stop-Process -Id $proc.Id -Force -ErrorAction SilentlyContinue
    }
    Start-Sleep -Seconds 1
}

function Stop-ProcessesInDirectory {
    param([string]$Dir)
    if ([string]::IsNullOrWhiteSpace($Dir) -or -not (Test-Path -LiteralPath $Dir)) { return }
    $root = (Get-Item -LiteralPath $Dir).FullName.TrimEnd('\') + '\'
    foreach ($proc in @(Get-Process -ErrorAction SilentlyContinue)) {
        try {
            $path = $proc.Path
            if ($null -ne $path -and $path.StartsWith($root, [StringComparison]::OrdinalIgnoreCase)) {
                Stop-Process -Id $proc.Id -Force -ErrorAction SilentlyContinue
            }
        } catch {}
    }
    Start-Sleep -Milliseconds 500
}

function Prepare-InstallDirectory {
    param([string]$TargetDir)
    Stop-YarMenuProcesses
    Stop-ProcessesInDirectory -Dir $TargetDir
    if (-not (Test-Path -LiteralPath $TargetDir)) {
        New-Item -ItemType Directory -Path $TargetDir -Force | Out-Null
        return
    }
    try {
        Remove-Item -LiteralPath $TargetDir -Recurse -Force -ErrorAction Stop
        New-Item -ItemType Directory -Path $TargetDir -Force | Out-Null
        return
    } catch {
        $parent = Split-Path $TargetDir -Parent
        $leaf = Split-Path $TargetDir -Leaf
        $archiveName = "${leaf}_old_$(Get-Date -Format 'yyyyMMddHHmmss')"
        $archivePath = Join-Path $parent $archiveName
        try {
            Rename-Item -LiteralPath $TargetDir -NewName $archiveName -ErrorAction Stop
            New-Item -ItemType Directory -Path $TargetDir -Force | Out-Null
            Start-Job -ScriptBlock {
                param($Path)
                Start-Sleep -Seconds 2
                Remove-Item -LiteralPath $Path -Recurse -Force -ErrorAction SilentlyContinue
            } -ArgumentList $archivePath | Out-Null
            return
        } catch {
            throw @"
Cannot update YarMenu POS - files are locked.

Close YarMenu POS and Print Agent, wait a few seconds, then click Install again.

$($_.Exception.Message)
"@
        }
    }
}

function Test-VcRedistInstalled {
    try {
        $key = 'HKLM:\SOFTWARE\Microsoft\VisualStudio\14.0\VC\Runtimes\x64'
        if (-not (Test-Path $key)) { return $false }
        return (Get-ItemProperty $key).Installed -eq 1
    } catch { return $false }
}

function Copy-AppTree {
    param([string]$From, [string]$To, [scriptblock]$OnProgress)
    $skip = @(
        'setup_gui.ps1', 'Setup.bat', 'Setup.vbs', 'Setup.launch.vbs', 'Setup.ps1',
        'register_windows_app.ps1', 'version.txt', 'README.txt', 'README-ar.txt',
        'setup.ico', 'setup_logo.png', 'vc_redist.x64.exe'
    )
    Prepare-InstallDirectory -TargetDir $To
    $files = Get-ChildItem -Path $From -Recurse -File | Where-Object {
        $_.Name -notin $skip -and $_.DirectoryName -notmatch '\\tools$'
    }
    $total = [Math]::Max(1, $files.Count)
    $i = 0
    foreach ($file in $files) {
        $rel = $file.FullName.Substring($From.Length).TrimStart('\')
        $dest = Join-Path $To $rel
        $parent = Split-Path $dest -Parent
        if (-not (Test-Path -LiteralPath $parent)) {
            New-Item -ItemType Directory -Path $parent -Force | Out-Null
        }
        for ($attempt = 1; $attempt -le 3; $attempt++) {
            try {
                Copy-Item -LiteralPath $file.FullName -Destination $dest -Force -ErrorAction Stop
                break
            } catch {
                if ($attempt -lt 3) {
                    Stop-YarMenuProcesses
                    Stop-ProcessesInDirectory -Dir $To
                    Start-Sleep -Seconds 2
                } else {
                    throw "Access denied copying: $rel`nClose YarMenu POS and try again.`n$($_.Exception.Message)"
                }
            }
        }
        $i++
        & $OnProgress ([int](($i / $total) * 100)) $rel
    }
}

function New-DesktopShortcut {
    param([string]$TargetExe, [string]$WorkDir)
    $desktop = [Environment]::GetFolderPath('Desktop')
    $lnk = Join-Path $desktop 'YarMenu POS.lnk'
    $wsh = New-Object -ComObject WScript.Shell
    $sc = $wsh.CreateShortcut($lnk)
    $sc.TargetPath = $TargetExe
    $sc.WorkingDirectory = $WorkDir
    $sc.Description = 'YarMenu Cashier (POS)'
    $sc.IconLocation = "$TargetExe,0"
    $sc.Save()
}

function New-FlatButton {
    param(
        [string]$Text,
        [System.Drawing.Color]$Back,
        [System.Drawing.Color]$Fore,
        [System.Drawing.Size]$Size,
        [System.Drawing.Font]$Font
    )
    $btn = New-Object System.Windows.Forms.Button
    $btn.Text = $Text
    $btn.Size = $Size
    $btn.BackColor = $Back
    $btn.ForeColor = $Fore
    $btn.FlatStyle = 'Flat'
    $btn.Font = $Font
    $btn.Cursor = [System.Windows.Forms.Cursors]::Hand
    $btn.FlatAppearance.BorderSize = 0
    return $btn
}

trap {
    [System.Windows.Forms.MessageBox]::Show(
        $_.Exception.Message,
        'YarMenu POS - Setup',
        [System.Windows.Forms.MessageBoxButtons]::OK,
        [System.Windows.Forms.MessageBoxIcon]::Error
    ) | Out-Null
    exit 1
}

$SourceDir = Resolve-InstallSourceDir $SourceDir
$ExeName = 'yarmenu_pos.exe'
$VcName = 'vc_redist.x64.exe'
$InstallDir = Join-Path $env:LOCALAPPDATA 'YarMenu\POS'
$RegisterScript = Join-Path $PSScriptRoot 'register_windows_app.ps1'
$BrandColor = [System.Drawing.Color]::FromArgb(0xE9, 0x25, 0x2E)
$BrandDark = [System.Drawing.Color]::FromArgb(0xC9, 0x1E, 0x26)
$TextMain = [System.Drawing.Color]::FromArgb(31, 41, 55)
$TextMuted = [System.Drawing.Color]::FromArgb(107, 114, 128)
$Surface = [System.Drawing.Color]::FromArgb(249, 250, 251)
$Border = [System.Drawing.Color]::FromArgb(229, 231, 235)

$sourceExe = Join-Path $SourceDir $ExeName
$brandAssets = Get-YarMenuBrandAssets -Dir $SourceDir

if (-not (Test-Path $sourceExe)) {
    [System.Windows.Forms.MessageBox]::Show(
        "File not found: $ExeName`n`nExtract the full ZIP folder first.",
        'YarMenu POS',
        [System.Windows.Forms.MessageBoxButtons]::OK,
        [System.Windows.Forms.MessageBoxIcon]::Error
    ) | Out-Null
    exit 1
}

$versionLabel = ''
$verFile = Join-Path $SourceDir 'version.txt'
if (Test-Path $verFile) { $versionLabel = (Get-Content $verFile -Raw).Trim() }

$form = New-Object System.Windows.Forms.Form
$form.Text = 'YarMenu POS'
$form.StartPosition = 'CenterScreen'
$form.FormBorderStyle = 'FixedDialog'
$form.MaximizeBox = $false
$form.MinimizeBox = $false
$form.ClientSize = New-UiSize 620 510
$form.BackColor = [System.Drawing.Color]::White
$form.Font = New-UiFont 'Segoe UI' 9.5
$form.Icon = $brandAssets.Icon
$form.AutoScaleMode = 'None'
$form.ShowInTaskbar = $true

$header = New-Object System.Windows.Forms.Panel
$header.Dock = 'Top'
$header.Height = 128
$header.BackColor = $BrandColor
$form.Controls.Add($header)

$logo = New-Object System.Windows.Forms.PictureBox
$logo.Size = New-UiSize 72 72
$logo.Location = New-UiPoint 24 24
$logo.SizeMode = 'Zoom'
$logo.BackColor = $BrandColor
$logo.Image = $brandAssets.Logo
$header.Controls.Add($logo)

$title = New-Object System.Windows.Forms.Label
$title.Text = 'YarMenu POS'
$title.ForeColor = [System.Drawing.Color]::White
$title.Font = New-UiFont 'Segoe UI' 20 ([System.Drawing.FontStyle]::Bold)
$title.AutoSize = $true
$title.Location = New-UiPoint 108 24
$header.Controls.Add($title)

$subtitle = New-Object System.Windows.Forms.Label
$subtitle.Text = 'Windows Cashier Setup'
$subtitle.ForeColor = [System.Drawing.Color]::FromArgb(255, 220, 224)
$subtitle.Font = New-UiFont 'Segoe UI' 10
$subtitle.AutoSize = $false
$subtitle.Size = New-UiSize 480 22
$subtitle.Location = New-UiPoint 108 56
$header.Controls.Add($subtitle)

if ($versionLabel) {
    $verBadge = New-Object System.Windows.Forms.Label
    $verBadge.Text = "v$versionLabel"
    $verBadge.ForeColor = [System.Drawing.Color]::FromArgb(255, 210, 214)
    $verBadge.Font = New-UiFont 'Segoe UI' 9
    $verBadge.AutoSize = $true
    $verBadge.Location = New-UiPoint 108 80
    $header.Controls.Add($verBadge)
}

$card = New-Object System.Windows.Forms.Panel
$card.Location = New-UiPoint 20 144
$card.Size = New-UiSize 580 190
$card.BackColor = $Surface
$form.Controls.Add($card)

$cardHeader = New-Object System.Windows.Forms.Label
$cardHeader.Text = 'Installation options'
$cardHeader.Font = New-UiFont 'Segoe UI' 11 ([System.Drawing.FontStyle]::Bold)
$cardHeader.ForeColor = $TextMain
$cardHeader.AutoSize = $true
$cardHeader.Location = New-UiPoint 18 14
$card.Controls.Add($cardHeader)

$cardBody = New-Object System.Windows.Forms.Label
$cardBody.Text = "Installs to:`n$InstallDir`n`nClose YarMenu POS before updating if files are locked."
$cardBody.Font = New-UiFont 'Segoe UI' 9
$cardBody.ForeColor = $TextMuted
$cardBody.Location = New-UiPoint 18 40
$cardBody.Size = New-UiSize 544 52
$card.Controls.Add($cardBody)

$chkVc = New-Object System.Windows.Forms.CheckBox
$chkVc.Text = 'Install Visual C++ Runtime (recommended)'
$chkVc.Checked = -not (Test-VcRedistInstalled)
$chkVc.Enabled = -not (Test-VcRedistInstalled)
$chkVc.AutoSize = $true
$chkVc.Font = New-UiFont 'Segoe UI' 9.5
$chkVc.ForeColor = $TextMain
$chkVc.Location = New-UiPoint 18 100
$card.Controls.Add($chkVc)

$chkDesktop = New-Object System.Windows.Forms.CheckBox
$chkDesktop.Text = 'Create desktop shortcut'
$chkDesktop.Checked = $true
$chkDesktop.AutoSize = $true
$chkDesktop.Font = New-UiFont 'Segoe UI' 9.5
$chkDesktop.ForeColor = $TextMain
$chkDesktop.Location = New-UiPoint 18 126
$card.Controls.Add($chkDesktop)

$chkLaunch = New-Object System.Windows.Forms.CheckBox
$chkLaunch.Text = 'Launch YarMenu POS when finished'
$chkLaunch.Checked = $true
$chkLaunch.AutoSize = $true
$chkLaunch.Font = New-UiFont 'Segoe UI' 9.5
$chkLaunch.ForeColor = $TextMain
$chkLaunch.Location = New-UiPoint 18 152
$card.Controls.Add($chkLaunch)

$progress = New-Object System.Windows.Forms.ProgressBar
$progress.Location = New-UiPoint 20 348
$progress.Size = New-UiSize 580 10
$progress.Style = 'Continuous'
$form.Controls.Add($progress)

$status = New-Object System.Windows.Forms.Label
$status.Text = 'Ready to install'
$status.Location = New-UiPoint 20 366
$status.Size = New-UiSize 580 40
$status.ForeColor = $TextMuted
$status.Font = New-UiFont 'Segoe UI' 9
$form.Controls.Add($status)

$btnFont = New-UiFont 'Segoe UI' 10 ([System.Drawing.FontStyle]::Bold)
$btnCancelFont = New-UiFont 'Segoe UI' 10

$btnCancel = New-FlatButton -Text 'Cancel' -Back $Surface -Fore $TextMain `
    -Size (New-UiSize 100 40) -Font $btnCancelFont
$btnCancel.Location = New-UiPoint 368 432
$btnCancel.FlatAppearance.BorderColor = $Border
$btnCancel.FlatAppearance.BorderSize = 1
$form.Controls.Add($btnCancel)

$btnInstall = New-FlatButton -Text 'Install' -Back $BrandColor -Fore ([System.Drawing.Color]::White) `
    -Size (New-UiSize 130 40) -Font $btnFont
$btnInstall.Location = New-UiPoint 478 432
$form.Controls.Add($btnInstall)

$btnInstall.Add_MouseEnter({ $btnInstall.BackColor = $BrandDark })
$btnInstall.Add_MouseLeave({ $btnInstall.BackColor = $BrandColor })

$btnCancel.Add_Click({ $form.Close() })

$btnInstall.Add_Click({
    $btnInstall.Enabled = $false
    $btnCancel.Enabled = $false
    $chkVc.Enabled = $false
    $chkDesktop.Enabled = $false
    $chkLaunch.Enabled = $false
    try {
        $progress.Value = 5
        $status.Text = 'Preparing...'

        if ($chkVc.Checked -and -not (Test-VcRedistInstalled)) {
            $vcPath = Join-Path $SourceDir $VcName
            if (-not (Test-Path $vcPath)) { throw "Missing $VcName - re-download the ZIP package." }
            $status.Text = 'Installing Visual C++...'
            $progress.Value = 15
            $p = Start-Process -FilePath $vcPath -ArgumentList '/install', '/quiet', '/norestart' -Wait -PassThru
            if ($p.ExitCode -gt 3010) { throw "Visual C++ installer exited with code $($p.ExitCode)" }
        }

        $progress.Value = 35
        $status.Text = 'Closing running YarMenu POS...'
        Stop-YarMenuProcesses
        Stop-ProcessesInDirectory -Dir $InstallDir
        $status.Text = 'Copying application files...'
        Copy-AppTree -From $SourceDir -To $InstallDir -OnProgress {
            param($pct, $name)
            $val = 35 + [int]($pct * 0.5)
            if ($val -gt 85) { $val = 85 }
            $progress.Value = $val
            $status.Text = "Copying: $name"
            [System.Windows.Forms.Application]::DoEvents()
        }

        $targetExe = Join-Path $InstallDir $ExeName
        if (Test-Path $RegisterScript) {
            $progress.Value = 88
            $status.Text = 'Registering in Windows...'
            $ver = if ($versionLabel) { $versionLabel } else { '0.0.0' }
            & $RegisterScript -InstallDir $InstallDir -Version $ver
        }

        if ($chkDesktop.Checked) {
            $progress.Value = 92
            $status.Text = 'Creating desktop shortcut...'
            New-DesktopShortcut -TargetExe $targetExe -WorkDir $InstallDir
        }

        $progress.Value = 100
        $status.Text = 'Installation complete'
        $status.ForeColor = $BrandColor

        if ($chkLaunch.Checked) {
            Start-Process -FilePath $targetExe -WorkingDirectory $InstallDir
        }

        [System.Windows.Forms.MessageBox]::Show(
            "Installation complete.`n`nFolder:`n$InstallDir`n`nSearch for YarMenu POS in Start menu or Settings > Apps.",
            'YarMenu POS',
            [System.Windows.Forms.MessageBoxButtons]::OK,
            [System.Windows.Forms.MessageBoxIcon]::Information
        ) | Out-Null
        $form.Close()
    } catch {
        $status.Text = $_.Exception.Message
        $status.ForeColor = [System.Drawing.Color]::DarkRed
        $btnInstall.Enabled = $true
        $btnCancel.Enabled = $true
        [System.Windows.Forms.MessageBox]::Show(
            $_.Exception.Message,
            'YarMenu POS - Setup error',
            [System.Windows.Forms.MessageBoxButtons]::OK,
            [System.Windows.Forms.MessageBoxIcon]::Error
        ) | Out-Null
    }
})

[void]$form.ShowDialog()
