#!/bin/bash
# =============================================================================
#  Rec — Builder & Installer
#  This script downloads the source (if needed), builds it locally on your Mac,
#  and generates an installable application bundle.
# =============================================================================

APP_NAME="Rec"
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
# =============================================================================
#  Repository Configuration (Update these for your internal GitHub instance)
# =============================================================================
REPO_BASE_URL="https://github.com/arunofhyd/Rec"
REPO_RAW_URL="https://raw.githubusercontent.com/arunofhyd/Rec/main"

APP_VERSION=""
# Try local version.json first, then fetch from GitHub
if [ -f version.json ]; then
    APP_VERSION=$(python3 -c "import json; print(json.load(open('version.json'))['version'])" 2>/dev/null || true)
elif [ -f "$SCRIPT_DIR/version.json" ]; then
    APP_VERSION=$(python3 -c "import json; print(json.load(open('$SCRIPT_DIR/version.json'))['version'])" 2>/dev/null || true)
fi
# If no local version.json, fetch it from the repo
if [ -z "$APP_VERSION" ]; then
    APP_VERSION=$(curl -fsSL "${REPO_RAW_URL}/version.json" 2>/dev/null | python3 -c "import json,sys; print(json.load(sys.stdin)['version'])" 2>/dev/null || true)
fi
if [ -z "$APP_VERSION" ]; then
    APP_VERSION=$(grep -m1 'appVersion' main.swift 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -n1 || true)
fi
if [ -z "$APP_VERSION" ]; then APP_VERSION="1.5.2"; fi

# ---- Terminal styling ------------------------------------
BOLD='\033[1m'; DIM='\033[2m'; NC='\033[0m'
BLUE='\033[38;5;39m'; GREEN='\033[38;5;35m'; YELLOW='\033[38;5;220m'; RED='\033[38;5;196m'; GREY='\033[38;5;245m'

line() { printf '%b\n' "${DIM}────────────────────────────────────────────────────────────${NC}"; }
step() { printf '%b▸%b %b%s%b\n' "${RED}${BOLD}" "${NC}" "${BOLD}" "$1" "${NC}"; }
ok()   { printf '  %b✓%b %s\n' "${GREEN}" "${NC}" "$1"; }
warn() { printf '  %b!%b %s\n' "${YELLOW}" "${NC}" "$1"; }
fail() { printf '  %b✗ %s%b\n' "${RED}" "$1" "${NC}"; }

clear
printf '\n'
printf '%b\n' "${RED}${BOLD}   Rec${NC}"
printf '%b\n\n' "${GREY}   Simple, clean, native-feeling screen recording.${NC}"
line
printf '\n'

# ---- Step 1: Command Line Tools (compiler) -------------------------------
step "Checking for build tools…"
if ! xcode-select -p >/dev/null 2>&1; then
    warn "Apple's Command Line Tools are needed to build the app."
    printf '%b\n\n' "  ${GREY}A small official Apple installer will pop up. Please click ${BOLD}Install${NC}${GREY} and wait for it to finish.${NC}"
    xcode-select --install >/dev/null 2>&1
    printf '%b' "  ${YELLOW}When the installation is COMPLETE, press [Enter] here to continue…${NC}"
    read -r
    if ! xcode-select -p >/dev/null 2>&1; then
        fail "Build tools still not found."
        printf '%b\n\n' "  ${GREY}Please finish the Apple installer, then run this file again.${NC}"
        exit 1
    fi
fi
ok "Build tools ready."
printf '\n'

# ---- Step 2: Workspace ----------------------------------------------------
step "Preparing a clean workspace…"
BUILD_DIR="$(mktemp -d)"
trap 'rm -rf "$BUILD_DIR"' EXIT
cd "$BUILD_DIR" || { fail "Could not create workspace."; exit 1; }

cat > Entitlements.plist <<'ENTEOF'
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>com.apple.security.device.audio-input</key>
    <true/>
    <key>com.apple.security.device.camera</key>
    <true/>
    <key>com.apple.security.cs.disable-library-validation</key>
    <true/>
</dict>
</plist>
ENTEOF

ok "Workspace ready."
printf '\n'

# ---- Step 3: Download the source -----------------------------------------
step "Downloading Rec source…"
if ! curl -fsSL "${REPO_RAW_URL}/main.swift" -o main.swift 2>/dev/null; then
    if [ -f "$OLDPWD/main.swift" ]; then
        cp "$OLDPWD/main.swift" .
    else
        fail "Could not download the app source."
        printf '%b\n\n' "  ${GREY}Check your internet connection and try again.${NC}"
        exit 1
    fi
fi
ok "Source ready."
printf '\n'


# ---- Step 3: Generate the app icon ---------------------------------------
step "Creating the app icon…"
cat > MakeIcon.swift <<'ICONEOF'
import Cocoa

let px: CGFloat = 1024
let img = NSImage(size: NSSize(width: px, height: px))
img.lockFocus()

guard let ctx = NSGraphicsContext.current?.cgContext else { fatalError() }

let padding: CGFloat = 100
let size = px - 2 * padding
ctx.translateBy(x: padding, y: padding)
let scale = size / px
ctx.scaleBy(x: scale, y: scale)

// Dark rounded rect background
let appScale = px / 120.0
ctx.scaleBy(x: appScale, y: appScale)

let bgPath = NSBezierPath(roundedRect: NSRect(x: 0, y: 0, width: 120, height: 120), xRadius: 27, yRadius: 27)
let topColor = NSColor(red: 51/255.0, green: 51/255.0, blue: 51/255.0, alpha: 1.0)
let botColor = NSColor(red: 26/255.0, green: 26/255.0, blue: 26/255.0, alpha: 1.0)
bgPath.addClip()
NSGradient(starting: topColor, ending: botColor)?.draw(in: bgPath, angle: -90)

// Shiny edges
let shineRect = CGRect(x: 1, y: 1, width: 118, height: 118)
let cgPath = CGPath(roundedRect: shineRect, cornerWidth: 26, cornerHeight: 26, transform: nil)
ctx.saveGState()
ctx.addPath(cgPath)
ctx.setLineWidth(2)
ctx.replacePathWithStrokedPath()
ctx.clip()
let shineGradient = NSGradient(colors: [
    NSColor.white.withAlphaComponent(0.6),
    NSColor.white.withAlphaComponent(0.0),
    NSColor.white.withAlphaComponent(0.0),
    NSColor.white.withAlphaComponent(0.6)
], atLocations: [0.0, 0.3, 0.7, 1.0], colorSpace: .deviceRGB)
shineGradient?.draw(in: NSRect(x: 0, y: 0, width: 120, height: 120), angle: -45)
ctx.restoreGState()

// Record Circle Outer
let outerPath = NSBezierPath(ovalIn: NSRect(x: 30, y: 30, width: 60, height: 60))
outerPath.lineWidth = 6
NSColor.white.setStroke()
outerPath.stroke()

// Record Circle Inner
let innerPath = NSBezierPath(ovalIn: NSRect(x: 40, y: 40, width: 40, height: 40))
NSColor(red: 1.0, green: 59/255.0, blue: 48/255.0, alpha: 1.0).setFill()
innerPath.fill()

img.unlockFocus()
if let tiff = img.tiffRepresentation,
   let rep = NSBitmapImageRep(data: tiff),
   let png = rep.representation(using: .png, properties: [:]) {
    try? png.write(to: URL(fileURLWithPath: "AppIcon.png"))
}
ICONEOF

swiftc MakeIcon.swift -o MakeIcon >/dev/null 2>&1 && ./MakeIcon
if [ -f AppIcon.png ]; then
    mkdir -p AppIcon.iconset
    for pair in "16 16x16" "32 16x16@2x" "32 32x32" "64 32x32@2x" "128 128x128" "256 128x128@2x" "256 256x256" "512 256x256@2x" "512 512x512" "1024 512x512@2x"; do
        set -- $pair
        sips -z "$1" "$1" AppIcon.png --out "AppIcon.iconset/icon_${2}.png" >/dev/null 2>&1
    done
    iconutil -c icns AppIcon.iconset >/dev/null 2>&1
    ok "Icon created."
else
    warn "Icon generation skipped (app will still work)."
fi
printf "\n"

# ---- Step 4: Assemble the app bundle -------------------------------------
step "Building ${APP_NAME}.app…"
APP="$APP_NAME.app"
rm -rf "$APP"
mkdir -p "$APP/Contents/MacOS" "$APP/Contents/Resources"
[ -f AppIcon.icns ] && cp AppIcon.icns "$APP/Contents/Resources/"

cat > "$APP/Contents/Info.plist" <<PLIST
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>CFBundleName</key><string>$APP_NAME</string>
  <key>CFBundleIdentifier</key><string>com.aoh.rec</string>
  <key>CFBundleVersion</key><string>$APP_VERSION</string>
  <key>CFBundleShortVersionString</key><string>$APP_VERSION</string>
  <key>CFBundleExecutable</key><string>$APP_NAME</string>
  <key>CFBundleIconFile</key><string>AppIcon</string>
  <key>CFBundlePackageType</key><string>APPL</string>
  <key>LSMinimumSystemVersion</key><string>13.0</string>
  <key>NSHighResolutionCapable</key><true/>
  <key>LSUIElement</key><true/>
  <key>NSScreenCaptureUsageDescription</key>
  <string>This app requires screen capture access to record your screen.</string>
  <key>NSMicrophoneUsageDescription</key>
  <string>This app needs access to the microphone and internal audio to record sound.</string>
  <key>NSCameraUsageDescription</key>
  <string>This app needs camera access to show a camera overlay during screen recording.</string>
  <key>CFBundleDocumentTypes</key>
  <array>
    <dict>
      <key>CFBundleTypeName</key>
      <string>Video</string>
      <key>CFBundleTypeRole</key>
      <string>Editor</string>
      <key>LSHandlerRank</key>
      <string>Alternate</string>
      <key>LSItemContentTypes</key>
      <array>
        <string>public.movie</string>
        <string>public.video</string>
        <string>com.apple.quicktime-movie</string>
        <string>public.mpeg-4</string>
        <string>public.avi</string>
      </array>
    </dict>
  </array>
</dict>
</plist>
PLIST

BUILD_OK=false
if swiftc -O -target arm64-apple-macos13.0 -o "${APP_NAME}_arm64" main.swift -framework Cocoa -framework ScreenCaptureKit -framework AVFoundation -framework VideoToolbox -framework SwiftUI -framework QuartzCore 2>build_errors.txt && \
   swiftc -O -target x86_64-apple-macos13.0 -o "${APP_NAME}_x86_64" main.swift -framework Cocoa -framework ScreenCaptureKit -framework AVFoundation -framework VideoToolbox -framework SwiftUI -framework QuartzCore 2>>build_errors.txt; then
    if lipo -create -output "$APP/Contents/MacOS/$APP_NAME" "${APP_NAME}_arm64" "${APP_NAME}_x86_64" 2>>build_errors.txt; then
        rm -f "${APP_NAME}_arm64" "${APP_NAME}_x86_64"
        BUILD_OK=true
    fi
fi

if [ "$BUILD_OK" != "true" ]; then
    warn "Local compilation failed."
    printf '%b\n' "  ${GREY}Falling back to downloading pre-built release...${NC}"
    
    ZIP_URL="${REPO_BASE_URL}/releases/download/v${APP_VERSION}/Rec.zip"
    if ! curl -fsSL "$ZIP_URL" -o Rec.zip; then
        ZIP_URL="${REPO_BASE_URL}/releases/latest/download/Rec.zip"
        curl -fsSL "$ZIP_URL" -o Rec.zip || { fail "Download failed."; exit 1; }
    fi
    
    rm -rf "$APP"
    unzip -o -q Rec.zip
    ok "Pre-built app downloaded successfully."
else
    chmod +x "$APP/Contents/MacOS/$APP_NAME"
    ENTITLEMENTS_FLAG=""
    [ -f Entitlements.plist ] && ENTITLEMENTS_FLAG="--entitlements Entitlements.plist"
    codesign --force --options runtime $ENTITLEMENTS_FLAG --sign - --requirements '=designated => identifier "com.aoh.rec"' "$APP" >/dev/null 2>&1 || true
    ok "App built."
fi
printf '\n'

if [ "$CI" = "true" ]; then
    mkdir -p "$OLDPWD/Build"
    cp -R "$APP" "$OLDPWD/Build/"
    ok "CI mode detected. App copied to Build/$APP"
    exit 0
fi

# ---- Step 5: Install to /Applications -------------------------------------
step "Installing Rec to /Applications…"

pkill -9 -x "$APP_NAME" >/dev/null 2>&1 || true
# Wait for process to fully exit (up to 5s)
attempts=0
while [ "$attempts" -lt 10 ] && pgrep -x "$APP_NAME" >/dev/null 2>&1; do
    sleep 0.5
    attempts=$((attempts + 1))
done
DEST="/Applications/$APP_NAME.app"
INSTALLED=false

if [ "$FORCE_MODAL" = "1" ] || [ "$1" = "--modal" ] || [ "$1" = "--gui" ] || [ "$2" = "--modal" ]; then
    INSTALLED=false
elif [ -w "/Applications" ]; then
    rm -rf "$DEST" 2>/dev/null || true
    if cp -R "$APP" "$DEST" 2>/dev/null; then
        INSTALLED=true
    fi
fi

if [ "$INSTALLED" = "true" ]; then
    xattr -dr com.apple.quarantine "$DEST" >/dev/null 2>&1 || true
    ok "Rec installed to /Applications."
    printf '\n'
    line
    printf '\n%b\n\n' "  ${GREEN}${BOLD}✓ Rec is installed and running!${NC}"
    printf '%b\n\n' "  ${GREY}Look for the floating record button on your screen.${NC}"
    open "$DEST"
    exit 0
fi

# Fallback: Build drag-and-drop installer modal if permission required
warn "Standard install required elevated privileges. Opening installer modal…"
cat > Installer.swift <<'INSTEOF'
import Cocoa
import QuartzCore

let appName = "Rec"
let sourcePath = CommandLine.arguments.count > 1 ? CommandLine.arguments[1] : ""

func getHighResIcon(path: String) -> NSImage {
    let icns = "\(path)/Contents/Resources/AppIcon.icns"
    if FileManager.default.fileExists(atPath: icns), let img = NSImage(contentsOfFile: icns) {
        img.size = NSSize(width: 128, height: 128)
        return img
    }
    let fallback = NSWorkspace.shared.icon(forFile: path)
    fallback.size = NSSize(width: 128, height: 128)
    return fallback
}

func performInstallation(src: URL) -> Bool {
    let dest = URL(fileURLWithPath: "/Applications").appendingPathComponent(src.lastPathComponent)
    do {
        if FileManager.default.fileExists(atPath: dest.path) {
            try FileManager.default.removeItem(at: dest)
        }
        try FileManager.default.copyItem(at: src, to: dest)
    } catch {
        let script = "do shell script \"rm -rf '/Applications/\(appName).app'; cp -R '\(src.path)' /Applications/\" with administrator privileges"
        if let s = NSAppleScript(source: script) {
            var err: NSDictionary?
            s.executeAndReturnError(&err)
            if err != nil {
                let a = NSAlert(); a.messageText = "Installation failed"
                a.informativeText = "Could not copy into Applications."
                a.runModal(); return false
            }
        }
    }
    let clean = Process()
    clean.launchPath = "/usr/bin/xattr"
    clean.arguments = ["-dr", "com.apple.quarantine", dest.path]
    clean.standardOutput = Pipe()
    clean.standardError = Pipe()
    try? clean.run(); clean.waitUntilExit()

    NSSound(named: "Glass")?.play()
    let a = NSAlert()
    a.messageText = "Rec installed!"
    a.informativeText = "Look for the floating record button."
    a.addButton(withTitle: "Launch Rec")
    a.addButton(withTitle: "Quit")
    if a.runModal() == .alertFirstButtonReturn { NSWorkspace.shared.open(dest) }
    NSApp.terminate(nil)
    return true
}

class ActionTarget: NSObject {
    @objc static func oneClickInstall() {
        if !sourcePath.isEmpty {
            let src = URL(fileURLWithPath: sourcePath)
            _ = performInstallation(src: src)
        }
    }
}

// Icon you can drag with crisp 2x Retina rendering.
class DragIcon: NSImageView, NSDraggingSource {
    var fileURL: URL?
    func draggingSession(_ s: NSDraggingSession, sourceOperationMaskFor c: NSDraggingContext) -> NSDragOperation { .copy }
    override func mouseDown(with event: NSEvent) {
        guard let url = fileURL, let originalImg = image else { return }
        let item = NSPasteboardItem()
        item.setString(url.absoluteString, forType: .fileURL)
        let drag = NSDraggingItem(pasteboardWriter: item)
        
        let dragImg = NSImage(size: bounds.size)
        dragImg.lockFocus()
        if let ctx = NSGraphicsContext.current {
            ctx.imageInterpolation = .high
        }
        originalImg.draw(in: bounds)
        dragImg.unlockFocus()
        
        drag.setDraggingFrame(bounds, contents: dragImg)
        beginDraggingSession(with: [drag], event: event, source: self)
    }
}

// The Applications folder drop target.
class DropZone: NSImageView {
    override init(frame f: NSRect) { super.init(frame: f); registerForDraggedTypes([.fileURL]) }
    required init?(coder: NSCoder) { super.init(coder: coder); registerForDraggedTypes([.fileURL]) }
    override func draggingEntered(_ s: NSDraggingInfo) -> NSDragOperation { .copy }
    override func performDragOperation(_ s: NSDraggingInfo) -> Bool {
        guard let str = s.draggingPasteboard.propertyList(forType: .fileURL) as? String,
              let src = URL(string: str) else { return false }
        return performInstallation(src: src)
    }
}

let app = NSApplication.shared
app.setActivationPolicy(.regular)

let W: CGFloat = 620, H: CGFloat = 410
let win = NSWindow(contentRect: NSRect(x: 0, y: 0, width: W, height: H),
                   styleMask: [.titled, .closable], backing: .buffered, defer: false)
win.title = "Install Rec"
win.center()

let bg = NSVisualEffectView(frame: NSRect(x: 0, y: 0, width: W, height: H))
bg.material = .windowBackground; bg.state = .active
win.contentView = bg

let title = NSTextField(labelWithString: "Install Rec")
title.frame = NSRect(x: 0, y: H - 65, width: W, height: 30)
title.alignment = .center
title.font = NSFont.systemFont(ofSize: 22, weight: .bold)
bg.addSubview(title)

let sub = NSTextField(labelWithString: "Drag Rec to Applications or click Instant Install below")
sub.frame = NSRect(x: 0, y: H - 90, width: W, height: 20)
sub.alignment = .center
sub.font = NSFont.systemFont(ofSize: 13)
sub.textColor = .secondaryLabelColor
bg.addSubview(sub)

let iconSize: CGFloat = 128
let midY: CGFloat = 145

// App icon (draggable)
let appIcon = DragIcon(frame: NSRect(x: 90, y: midY, width: iconSize, height: iconSize))
appIcon.imageScaling = .scaleProportionallyUpOrDown
appIcon.image = getHighResIcon(path: sourcePath)
appIcon.fileURL = URL(fileURLWithPath: sourcePath)
bg.addSubview(appIcon)

let appLabel = NSTextField(labelWithString: appName)
appLabel.frame = NSRect(x: 90, y: midY - 26, width: iconSize, height: 18)
appLabel.alignment = .center
appLabel.font = NSFont.systemFont(ofSize: 12, weight: .medium)
bg.addSubview(appLabel)

// Gradient Arrow View (Fading Stem Arrow)
class GradientArrowView: NSView {
    override func draw(_ dirtyRect: NSRect) {
        super.draw(dirtyRect)
        let w = bounds.width
        let h = bounds.height
        let midY = h / 2.0
        
        let stemH: CGFloat = 10
        let headH: CGFloat = 26
        let headW: CGFloat = 20
        let stemR = w - headW
        
        let path = NSBezierPath()
        path.move(to: NSPoint(x: 0, y: midY - stemH/2))
        path.line(to: NSPoint(x: stemR, y: midY - stemH/2))
        path.line(to: NSPoint(x: stemR, y: midY - headH/2))
        path.line(to: NSPoint(x: w, y: midY))
        path.line(to: NSPoint(x: stemR, y: midY + headH/2))
        path.line(to: NSPoint(x: stemR, y: midY + stemH/2))
        path.line(to: NSPoint(x: 0, y: midY + stemH/2))
        path.close()
        
        let startColor = NSColor.labelColor.withAlphaComponent(0.0)
        let endColor = NSColor.labelColor.withAlphaComponent(0.50)
        let gradient = NSGradient(starting: startColor, ending: endColor)
        gradient?.draw(in: path, angle: 0)
    }
}

let arrow = GradientArrowView(frame: NSRect(x: (W - 70)/2, y: midY + iconSize/2 - 18, width: 70, height: 36))
bg.addSubview(arrow)

// Applications folder (drop zone)
let drop = DropZone(frame: NSRect(x: W - 90 - iconSize, y: midY, width: iconSize, height: iconSize))
drop.imageScaling = .scaleProportionallyUpOrDown
let appsIcon = NSWorkspace.shared.icon(forFile: "/Applications")
appsIcon.size = NSSize(width: 128, height: 128)
drop.image = appsIcon
bg.addSubview(drop)

let appsLabel = NSTextField(labelWithString: "Applications")
appsLabel.frame = NSRect(x: W - 90 - iconSize, y: midY - 26, width: iconSize, height: 18)
appsLabel.alignment = .center
appsLabel.font = NSFont.systemFont(ofSize: 12, weight: .medium)
bg.addSubview(appsLabel)

class AnimatedInstallButton: NSButton {
    private var trackingArea: NSTrackingArea?
    private var isHovered = false { didSet { animateState() } }
    private var isPressed = false { didSet { animateState() } }

    override init(frame frameRect: NSRect) {
        super.init(frame: frameRect)
        setup()
    }
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        setup()
    }
    private func setup() {
        wantsLayer = true
        isBordered = false
        focusRingType = .none
        layer?.cornerRadius = 10
        layer?.backgroundColor = NSColor(red: 0.18, green: 0.18, blue: 0.20, alpha: 1.0).cgColor
        contentTintColor = .white
    }
    override func updateTrackingAreas() {
        super.updateTrackingAreas()
        if let area = trackingArea { removeTrackingArea(area) }
        let area = NSTrackingArea(rect: bounds, options: [.mouseEnteredAndExited, .activeAlways], owner: self, userInfo: nil)
        addTrackingArea(area)
        trackingArea = area
    }
    override func mouseEntered(with event: NSEvent) {
        isHovered = true
        NSCursor.pointingHand.set()
    }
    override func mouseExited(with event: NSEvent) {
        isHovered = false
        NSCursor.arrow.set()
    }
    override func mouseDown(with event: NSEvent) {
        isPressed = true
        super.mouseDown(with: event)
    }
    override func mouseUp(with event: NSEvent) {
        isPressed = false
        super.mouseUp(with: event)
    }
    private func animateState() {
        NSAnimationContext.runAnimationGroup { ctx in
            ctx.duration = 0.15
            ctx.allowsImplicitAnimation = true
            if isPressed {
                layer?.backgroundColor = NSColor(red: 0.14, green: 0.14, blue: 0.16, alpha: 1.0).cgColor
                layer?.transform = CATransform3DMakeScale(0.95, 0.95, 1.0)
            } else if isHovered {
                layer?.backgroundColor = NSColor(red: 0.28, green: 0.28, blue: 0.30, alpha: 1.0).cgColor
                layer?.transform = CATransform3DMakeScale(1.04, 1.04, 1.0)
                layer?.shadowColor = NSColor.black.cgColor
                layer?.shadowRadius = 8
                layer?.shadowOpacity = 0.35
                layer?.shadowOffset = .zero
            } else {
                layer?.backgroundColor = NSColor(red: 0.18, green: 0.18, blue: 0.20, alpha: 1.0).cgColor
                layer?.transform = CATransform3DIdentity
                layer?.shadowOpacity = 0
            }
        }
    }
}

// Instant 1-Click Install Button
let installBtn = AnimatedInstallButton(frame: NSRect(x: (W - 270)/2, y: 35, width: 270, height: 42))
installBtn.title = "⚡ One-Click Install to /Applications"
installBtn.font = NSFont.systemFont(ofSize: 13, weight: .bold)
installBtn.target = ActionTarget.self
installBtn.action = #selector(ActionTarget.oneClickInstall)
bg.addSubview(installBtn)

win.makeKeyAndOrderFront(nil)
app.activate(ignoringOtherApps: true)
app.run()
INSTEOF

if swiftc -O -o Installer Installer.swift -framework Cocoa >/dev/null 2>&1; then
    ./Installer "$BUILD_DIR/$APP"
else
    osascript -e "do shell script \"rm -rf '$DEST'; cp -R '$BUILD_DIR/$APP' '/Applications/'\" with administrator privileges" >/dev/null 2>&1 || true
    xattr -dr com.apple.quarantine "$DEST" >/dev/null 2>&1 || true
    open "$DEST"
fi
printf "\n"