app := "restray"
version := `grep 'const version' cmd/restray/main.go | cut -d'"' -f2`
bin := "bin"
dist := "dist"
pkg := "cmd/restray"
icon := "cmd/restray/icons/icon.png"

icons:
    #!/usr/bin/env bash
    set -euo pipefail
    tmp=$(mktemp -d)
    trap 'rm -rf "$tmp"' EXIT
    out="{{pkg}}/icons/generated"
    rm -rf "$out"
    mkdir -p "$out"
    oxipng -r -o max -z --strip all -a "{{pkg}}/icons"
    for sheet in idle busy fail download; do
        src="{{pkg}}/icons/$sheet.png"
        [ -f "$src" ] || continue
        read -r w sz < <(magick identify -format "%w %h\n" "$src")
        cols=$((w / sz))
        for ((i=0; i<cols; i++)); do
            x=$((i * sz))
            n=$(printf "%02d" "$i")
            magick "$src" -crop "${sz}x${sz}+${x}+0" +repage "$tmp/color.png"
            magick "$tmp/color.png" -alpha extract -background white -alpha shape "$tmp/white.png"
            magick "$tmp/color.png" -alpha extract -background black -alpha shape "$tmp/black.png"
            for variant in color white black; do
                mv "$tmp/$variant.png" "$out/${variant}-${sheet}-${n}.png"
                oxipng -o max -z --strip all -a "$out/${variant}-${sheet}-${n}.png"
                magick "$out/${variant}-${sheet}-${n}.png" -define icon:auto-resize=32,16 "$out/${variant}-${sheet}-${n}.ico"
            done
        done
    done
    cp {{icon}} packaging/linux/restray.png
    magick {{icon}} -define icon:auto-resize=256,128,64,48,32,16 packaging/windows/restray.ico
    go run github.com/tc-hib/go-winres@v0.3.3 simply --arch amd64,arm64 --manifest gui --icon packaging/windows/restray.ico --out packaging/windows/restray
    sizes=()
    for size in 16 32 128 256 512; do
        magick {{icon}} -resize ${size}x${size} "$tmp/restray-${size}.png"
        sizes+=("$tmp/restray-${size}.png")
    done
    png2icns packaging/darwin/restray.icns "${sizes[@]}"

build target="" arch="":
    #!/usr/bin/env bash
    set -euo pipefail
    mkdir -p {{bin}}
    zig_arch() {
        case "$1" in
            amd64) echo "x86_64" ;;
            arm64) echo "aarch64" ;;
            *)     echo "$1" ;;
        esac
    }
    build_one() {
        local os=$1 arch=$2 za
        za=$(zig_arch "$arch")
        local ldflags="-s -w"
        case "$os" in
            darwin)
                local sdk cc
                unset DEVELOPER_DIR NIX_CFLAGS_COMPILE NIX_LDFLAGS NIX_CC
                sdk=$(env -u DEVELOPER_DIR /usr/bin/xcrun --sdk macosx --show-sdk-path)
                cc=$(env -u DEVELOPER_DIR /usr/bin/xcrun --sdk macosx --find clang)
                CC="$cc" \
                SDKROOT="$sdk" \
                MACOSX_DEPLOYMENT_TARGET="12.0" \
                CGO_CFLAGS="-isysroot $sdk -mmacosx-version-min=12.0" \
                CGO_LDFLAGS="-isysroot $sdk -mmacosx-version-min=12.0" \
                GOOS=darwin GOARCH=$arch \
                go build -trimpath -ldflags "$ldflags -extld=$cc" -o {{bin}}/{{app}}-{{version}}-darwin-$arch ./{{pkg}} ;;
            linux)
                CGO_ENABLED=1 CC="zig cc -target ${za}-linux-gnu" \
                GOOS=linux GOARCH=$arch go build -trimpath -ldflags "$ldflags" -o {{bin}}/{{app}}-{{version}}-linux-$arch ./{{pkg}} ;;
            windows)
                (
                    resource="packaging/windows/restray_windows_${arch}.syso"
                    copied_resource="{{pkg}}/restray_windows_${arch}.syso"
                    trap 'rm -f "$copied_resource"' EXIT
                    cp -f "$resource" "$copied_resource"
                    CGO_ENABLED=1 CC="zig cc -target ${za}-windows-gnu" \
                    GOOS=windows GOARCH=$arch go build -trimpath -ldflags "$ldflags -H=windowsgui" -o {{bin}}/{{app}}-{{version}}-windows-$arch.exe ./{{pkg}}
                ) ;;
        esac
    }
    build_os() {
        local os=$1
        if [ -n "{{arch}}" ]; then
            build_one "$os" "{{arch}}"
        else
            build_one "$os" amd64
            build_one "$os" arm64
        fi
    }
    case "{{target}}" in
        darwin|linux|windows) build_os "{{target}}" ;;
        all) build_os darwin; build_os linux; build_os windows ;;
        "") build_one "$(go env GOOS)" "$(go env GOARCH)" ;;
        *) echo "Unknown target: {{target}}. Use: darwin, linux, windows, all"; exit 1 ;;
    esac

package target="" arch="":
    #!/usr/bin/env bash
    set -euo pipefail
    package_one() {
        local os=$1 arch=$2
        just build "$os" "$arch"
        just "_package-$os" "$arch"
    }
    package_os() {
        local os=$1
        if [ -n "{{arch}}" ]; then
            package_one "$os" "{{arch}}"
        else
            package_one "$os" amd64
            package_one "$os" arm64
        fi
    }
    case "{{target}}" in
        darwin|windows) package_os "{{target}}" ;;
        all) package_os darwin; package_os windows ;;
        "")
            case "$(uname)" in
                Darwin)       package_os darwin ;;
                MINGW*|MSYS*) package_os windows ;;
                *)            echo "No packaging for Linux; use 'just build linux' instead"; exit 1 ;;
            esac ;;
        *) echo "Unknown target: {{target}}. Use: darwin, windows, all"; exit 1 ;;
    esac

_package-darwin arch:
    #!/usr/bin/env bash
    set -euo pipefail
    rm -rf {{dist}}/Restray.app
    mkdir -p {{dist}}/Restray.app/Contents/MacOS {{dist}}/Restray.app/Contents/Resources
    trap 'rm -rf {{dist}}/Restray.app' EXIT
    cp {{bin}}/{{app}}-{{version}}-darwin-{{arch}} {{dist}}/Restray.app/Contents/MacOS/Restray
    cp packaging/darwin/Info.plist {{dist}}/Restray.app/Contents/Info.plist
    cp packaging/darwin/restray.icns {{dist}}/Restray.app/Contents/Resources/restray.icns
    just _fetch-restic-darwin {{arch}}
    cp {{bin}}/restic-darwin-{{arch}} {{dist}}/Restray.app/Contents/Resources/restic
    chmod +x {{dist}}/Restray.app/Contents/Resources/restic
    just _fetch-rustic-darwin {{arch}}
    cp {{bin}}/rustic-darwin-{{arch}} {{dist}}/Restray.app/Contents/Resources/rustic
    chmod +x {{dist}}/Restray.app/Contents/Resources/rustic
    while IFS= read -r file; do
        references=$( { otool -l "$file" 2>/dev/null || true; } | grep '/nix/store/' || true)
        [ -z "$references" ] || {
            echo "$file references the Nix store:" >&2
            echo "$references" >&2
            exit 1
        }
    done < <(find {{dist}}/Restray.app/Contents -type f)
    /usr/bin/ditto -c -k --sequesterRsrc --keepParent {{dist}}/Restray.app {{dist}}/{{app}}-{{version}}-darwin-{{arch}}-app.zip

_fetch-restic-darwin arch:
    #!/usr/bin/env bash
    set -euo pipefail
    out="{{bin}}/restic-darwin-{{arch}}"
    [ -f "$out" ] && exit 0
    mkdir -p {{bin}}
    tmp=$(mktemp -d)
    trap 'rm -rf "$tmp"' EXIT
    version=$(curl -fsSL https://api.github.com/repos/restic/restic/releases/latest | sed -n 's/.*"tag_name": *"v\([^"]*\)".*/\1/p')
    [ -n "$version" ]
    curl -fsSL -o "$tmp/restic.bz2" "https://github.com/restic/restic/releases/download/v${version}/restic_${version}_darwin_{{arch}}.bz2"
    bunzip2 -c "$tmp/restic.bz2" > "$tmp/restic"
    chmod +x "$tmp/restic"
    mv "$tmp/restic" "$out"

_fetch-rustic-darwin arch:
    #!/usr/bin/env bash
    set -euo pipefail
    out="{{bin}}/rustic-darwin-{{arch}}"
    [ -f "$out" ] && exit 0
    mkdir -p {{bin}}
    tmp=$(mktemp -d)
    trap 'rm -rf "$tmp"' EXIT
    version=$(curl -fsSL https://api.github.com/repos/rustic-rs/rustic/releases/latest | sed -n 's/.*"tag_name": *"v\([^"]*\)".*/\1/p')
    [ -n "$version" ]
    case "{{arch}}" in
      amd64) target=x86_64-apple-darwin ;;
      arm64) target=aarch64-apple-darwin ;;
      *) echo "unsupported macOS architecture: {{arch}}" >&2; exit 1 ;;
    esac
    curl -fsSL -o "$tmp/rustic.tar.gz" "https://github.com/rustic-rs/rustic/releases/download/v${version}/rustic-v${version}-${target}.tar.gz"
    tar -xzf "$tmp/rustic.tar.gz" -C "$tmp"
    binary=$(find "$tmp" -type f -name rustic -perm -111 -print -quit)
    [ -n "$binary" ]
    chmod +x "$binary"
    mv "$binary" "$out"

_package-windows arch:
    #!/usr/bin/env bash
    set -euo pipefail
    mkdir -p {{dist}}
    makensis -DARCH={{arch}} packaging/windows/installer.nsi

run:
    just build && {{bin}}/{{app}}-{{version}}-$(go env GOOS)-$(go env GOARCH)

check:
    just lint
    just test

lint:
    goimports -w {{pkg}}
    go vet ./{{pkg}}
    staticcheck ./{{pkg}}

test:
    go test ./...

test-race:
    go test -race ./...

bump new:
    #!/usr/bin/env bash
    set -euo pipefail
    current="{{version}}"
    new="{{new}}"
    case "$new" in
        patch|minor|major)
            IFS=. read -r current_major current_minor current_patch <<< "$current"
            case "$new" in
                patch) new="$current_major.$current_minor.$((current_patch + 1))" ;;
                minor) new="$current_major.$((current_minor + 1)).0" ;;
                major) new="$((current_major + 1)).0.0" ;;
            esac ;;
    esac
    [[ "$new" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] || { echo "Usage: just bump X.Y.Z|patch|minor|major"; exit 1; }
    perl -pi -e "s/^const version = \".*\"/const version = \"$new\"/" {{pkg}}/main.go
    perl -pi -e "s/version = \".*\"/version = \"$new\"/" flake.nix
    perl -pi -e "s/!define VERSION \".*\"/!define VERSION \"$new\"/" packaging/windows/installer.nsi
    perl -pi -e 's|(<string>)[^<]*(</string>)|${1}'"$new"'${2}| if $prev =~ /CFBundle(Version|ShortVersionString)/; $prev = $_' packaging/darwin/Info.plist
    echo "Bumped to $new"
    grep -n "$new" {{pkg}}/main.go flake.nix packaging/windows/installer.nsi packaging/darwin/Info.plist

clean:
    rm -rf {{bin}} {{dist}} result
