# TUICommander Makefile
# Builds, signs, and packages the Tauri app for macOS distribution

APP_NAME=TUICommander
BINARY_NAME=tuicommander
BUNDLE_ID=com.tuic.commander
VERSION=$(shell git describe --tags --always --dirty 2>/dev/null || echo "dev")

# Code signing identity: override with SIGN_IDENTITY env var.
# Auto-detection order: Developer ID > ad-hoc.
SIGN_IDENTITY?=-

# Tauri build output
TAURI_TARGET=src-tauri/target/release/bundle/macos
APP_BUNDLE=$(TAURI_TARGET)/$(APP_NAME).app

# whisper-rs-sys bundles whisper.cpp which uses std::filesystem::path (macOS 10.15+).
# Must be exported so CMake subprocesses inherit it (.cargo/config.toml [env] alone is insufficient).
export MACOSX_DEPLOYMENT_TARGET ?= 10.15

# Distribution output
DIST_DIR=dist-release

.PHONY: all clean dev test build build-dmg check fmt sign verify-sign notarize release dist \
       nightly github-release preview bump release-notes \
       gh-debug-on gh-debug-off gh-debug-status gh-debug-logs gh-rate logs

all: build sign

# Run in development mode with hot reload (debug tracing for our code only)
# Pre-builds frontend so the PWA (served from dist/) is up to date.
dev:
	@pnpm exec vite build
	TAURI_CLI_WATCHER_IGNORE_FILENAME=.taurignore RUST_LOG=tuicommander_lib=debug,info pnpm tauri dev

# Build frontend + launch Tauri dev (for quick manual testing)
test:
	@echo "Building Vite frontend..."
	@pnpm exec vite build
	@echo "Starting Tauri dev..."
	TAURI_CLI_WATCHER_IGNORE_FILENAME=.taurignore pnpm tauri dev

# Build .app only (default, fast — skips DMG)
build:
	@echo "Building TUICommander $(VERSION)..."
	pnpm tauri build

# Build .app + DMG (for distribution)
build-dmg:
	@echo "Building TUICommander $(VERSION) with DMG..."
	pnpm tauri build --bundles app,dmg

# Auto-format frontend + Rust
fmt:
	@pnpm exec biome check --fix src/
	@cd src-tauri && cargo fmt

# Type-check, lint, format, and test (no Tauri build)
check:
	@echo "Running checks..."
	@rtk pnpm exec tsc --noEmit && echo "  tsc ✓"
	@rtk pnpm exec biome check --max-diagnostics=100 src/ && echo "  biome ✓"
	@cd src-tauri && rtk cargo fmt --check && echo "  rustfmt ✓"
	@cd src-tauri && rtk cargo clippy --release -- -D warnings && echo "  clippy ✓"
	@cd src-tauri && ulimit -n 10240 && rtk cargo test -q && echo "  cargo test ✓"
	@rtk pnpm exec vitest run --reporter=dot 2>&1 | tail -3
	@rtk pnpm audit --audit-level=high && echo "  pnpm audit ✓"
	@cd src-tauri && rtk err cargo audit -q --ignore RUSTSEC-2026-0097 --ignore RUSTSEC-2023-0071 && echo "  cargo audit ✓"

# GitHub API debug logging — toggle at runtime, view logs
gh-debug-on:
	@curl -s -X POST localhost:9876/repo/github-poller/api-debug -H 'Content-Type: application/json' -d '{"enabled":true}' && echo ""

gh-debug-off:
	@curl -s -X POST localhost:9876/repo/github-poller/api-debug -H 'Content-Type: application/json' -d '{"enabled":false}' && echo ""

gh-debug-status:
	@curl -s localhost:9876/repo/github-poller/api-debug && echo ""

gh-debug-logs:
	@curl -s 'localhost:9876/logs?source=github_api&limit=30'

# Tail recent terminal logs (needs Remote Access enabled in Settings).
# Override source/limit: make logs SRC=mcp N=100
logs:
	@curl -s "localhost:9876/logs?source=$(or $(SRC),terminal)&limit=$(or $(N),50)"

gh-rate:
	@curl -sH "Authorization: Bearer $$(gh auth token)" https://api.github.com/rate_limit | jq '.resources | {graphql, core}'

# Sign the built .app bundle
sign:
	@# Auto-detect best available signing certificate
	@if [ "$(SIGN_IDENTITY)" != "-" ]; then \
		SIGN_ID="$(SIGN_IDENTITY)"; \
	else \
		SIGN_ID=$$(security find-identity -v -p codesigning 2>/dev/null | grep "Developer ID Application:" | head -1 | sed 's/.*"\(.*\)".*/\1/'); \
		if [ -z "$$SIGN_ID" ]; then \
			echo "WARNING: No Developer ID found — using ad-hoc signing. Recipients will need to right-click > Open."; \
			SIGN_ID="-"; \
		fi; \
	fi; \
	echo "Signing with: $$SIGN_ID"; \
	codesign --force --deep --sign "$$SIGN_ID" \
		--entitlements src-tauri/Entitlements.plist \
		--identifier "$(BUNDLE_ID)" \
		--options runtime \
		"$(APP_BUNDLE)"; \
	echo "Signed: $(APP_BUNDLE)"

# Verify code signature
verify-sign:
	codesign -dvvv "$(APP_BUNDLE)"

# Notarize with Apple (requires stored credentials).
# First run: xcrun notarytool store-credentials "TUICommander" --apple-id YOUR_ID --team-id YOUR_TEAM
notarize: sign
	@echo "Creating zip for notarization..."
	@mkdir -p $(DIST_DIR)
	ditto -c -k --keepParent "$(APP_BUNDLE)" "$(DIST_DIR)/$(BINARY_NAME)-notarize.zip"
	@echo "Submitting to Apple notary service..."
	xcrun notarytool submit "$(DIST_DIR)/$(BINARY_NAME)-notarize.zip" --keychain-profile "TUICommander" --wait
	@echo "Stapling notarization ticket..."
	xcrun stapler staple "$(APP_BUNDLE)"
	@rm -f "$(DIST_DIR)/$(BINARY_NAME)-notarize.zip"
	@echo "Notarization complete."

# Build, sign, notarize, and create distributable zip
release: build-dmg sign notarize
	@echo "Creating distributable zip..."
	@mkdir -p $(DIST_DIR)
	ditto -c -k --keepParent "$(APP_BUNDLE)" "$(DIST_DIR)/$(BINARY_NAME)-$(VERSION).zip"
	@echo "Release artifact: $(DIST_DIR)/$(BINARY_NAME)-$(VERSION).zip"
	@ls -lh "$(DIST_DIR)/$(BINARY_NAME)-$(VERSION).zip"

# Quick distribution without notarization (friends can right-click > Open)
dist: build sign
	@echo "Creating distributable zip (not notarized)..."
	@mkdir -p $(DIST_DIR)
	ditto -c -k --keepParent "$(APP_BUNDLE)" "$(DIST_DIR)/$(BINARY_NAME)-$(VERSION).zip"
	@echo "Distributable: $(DIST_DIR)/$(BINARY_NAME)-$(VERSION).zip"
	@echo "NOTE: Recipients must right-click > Open on first launch (not notarized)."
	@ls -lh "$(DIST_DIR)/$(BINARY_NAME)-$(VERSION).zip"

# --- GitHub CI workflows ---

# Push main to origin, triggering the Nightly workflow (builds tip release).
# Also force-moves the tip git tag to HEAD so the release points to the latest commit.
# Usage: make nightly
nightly:
	@BRANCH=$$(git rev-parse --abbrev-ref HEAD); \
	if [ "$$BRANCH" != "main" ]; then echo "ERROR: must be on main (currently on $$BRANCH)" && exit 1; fi; \
	if [ -n "$$(git status --porcelain)" ]; then echo "ERROR: working tree is dirty — commit or stash first" && exit 1; fi; \
	echo "==> Pushing main and updating tip tag..."; \
	git tag -f tip; \
	git push origin main; \
	git push origin tip --force; \
	echo "==> Nightly triggered. Monitor: gh run list -w Nightly --limit 1"

# Bump version across all manifests (no commit, no tag).
# Usage: make bump V=0.6.2
bump:
	@if [ -z "$(V)" ]; then echo "ERROR: specify version with V=x.y.z" && exit 1; fi; \
	CUR=$$(grep '^version' src-tauri/Cargo.toml | head -1 | sed 's/.*"\(.*\)"/\1/'); \
	echo "==> Bumping $$CUR → $(V)"; \
	sed -i '' '/^\[package\]/,/^\[/ s/^version = ".*"/version = "$(V)"/' src-tauri/Cargo.toml; \
	sed -i '' 's/"version": "[^"]*"/"version": "$(V)"/' src-tauri/tauri.conf.json; \
	sed -i '' 's/^  "version": "[^"]*"/  "version": "$(V)"/' package.json; \
	sed -i '' '/^\[package\]/,/^\[/ s/^version = ".*"/version = "$(V)"/' src-tauri/crates/tuic-bridge/Cargo.toml; \
	echo "  src-tauri/Cargo.toml  → $(V)"; \
	echo "  src-tauri/crates/tuic-bridge/Cargo.toml → $(V)"; \
	echo "  src-tauri/tauri.conf.json → $(V)"; \
	echo "  package.json          → $(V)"; \
	sed -i '' 's/^\*\*Version:\*\* .*/**Version:** $(V)/' SPEC.md; \
	echo "  SPEC.md               → $(V)"; \
	TODAY=$$(date +%Y-%m-%d); \
	sed -i '' 's/^## \[Unreleased\]/## [Unreleased]\n\n## [$(V)] - '"$$TODAY"'/' CHANGELOG.md; \
	echo "  CHANGELOG.md          → $(V) ($$TODAY)"; \
	echo "  release-notes.json   → generating..."; \
	./scripts/generate-release-notes.sh $(V); \
	echo "==> Done. Run 'cargo check' or 'make github-release' to continue."

# Generate AI-written release notes for a specific version.
# Usage: make release-notes V=1.3.0
release-notes:
	@if [ -z "$(V)" ]; then echo "ERROR: specify version with V=x.y.z" && exit 1; fi; \
	./scripts/generate-release-notes.sh $(V)

# Full versioned release: tag current version, push, wait for CI, publish.
# To bump first: make bump BUMP=patch (or minor|major), then make github-release.
# NOTE: sed -i '' is macOS syntax — run this from macOS only.
github-release:
	@BRANCH=$$(git rev-parse --abbrev-ref HEAD); \
	if [ "$$BRANCH" != "main" ]; then echo "ERROR: must be on main (currently on $$BRANCH)" && exit 1; fi; \
	if [ -n "$$(git status --porcelain)" ]; then echo "ERROR: working tree is dirty — commit or stash first" && exit 1; fi; \
	CUR=$$(grep '^version' src-tauri/Cargo.toml | head -1 | sed 's/.*"\(.*\)"/\1/'); \
	TAG="v$$CUR"; \
	if git rev-parse "$$TAG" >/dev/null 2>&1; then echo "ERROR: tag $$TAG already exists" && exit 1; fi; \
	echo "==> Releasing $$TAG"; \
	git tag "$$TAG"; \
	COMMIT=$$(git rev-parse HEAD); \
	echo "--- Pushing..."; \
	git push origin main --tags; \
	echo "--- Waiting for Release workflow on $$COMMIT..."; \
	sleep 10; \
	RUN_ID=""; \
	for i in 1 2 3 4 5; do \
		RUN_ID=$$(gh run list -w Release --limit 5 --json databaseId,headSha --jq ".[] | select(.headSha == \"$$COMMIT\") | .databaseId" | head -1); \
		if [ -n "$$RUN_ID" ]; then break; fi; \
		echo "  run not found yet, retrying ($$i/5)..."; \
		sleep 5; \
	done; \
	if [ -z "$$RUN_ID" ]; then echo "ERROR: no Release workflow run found for $$COMMIT" && exit 1; fi; \
	echo "--- Watching run $$RUN_ID (Ctrl+C to detach)..."; \
	gh run watch "$$RUN_ID" --exit-status; \
	echo "--- Publishing draft release..."; \
	gh release edit "$$TAG" --draft=false; \
	echo "==> Released: $$(gh release view $$TAG --json url --jq .url)"

# Build a debug preview with a different app name to avoid conflicts with the real app.
# The resulting .app is named "TUIC-preview" with a separate bundle ID, so macOS and
# tests won't confuse it with the production TUICommander.
# Uses --debug for fast iteration; full release build only on github-release.
preview:
	@pnpm exec vite build
	@echo "Building TUIC-preview $(VERSION) (debug mode)..."
	pnpm tauri build --debug --bundles app --config '{"productName":"TUIC-preview","identifier":"com.tuic.preview","bundle":{"createUpdaterArtifacts":false},"app":{"windows":[{"title":"TUIC-preview","width":1200,"height":800,"minWidth":800,"minHeight":600,"decorations":true,"transparent":false,"resizable":true,"fullscreen":false,"hiddenTitle":true,"titleBarStyle":"Overlay","trafficLightPosition":{"x":13,"y":20},"backgroundColor":"#000000","dragDropEnabled":true}]}}'
	@echo "Launching TUIC-preview..."
	open "src-tauri/target/debug/bundle/macos/TUIC-preview.app"

# Clean build artifacts
clean:
	rm -rf $(DIST_DIR)
	cd src-tauri && cargo clean
