.PHONY: \
	lint test clean \
	version-sync version-check version-bump \
	server-run server-build server-lint server-test server-clean \
	desktop-build-mac desktop-build-win desktop-build-linux \
	desktop-lint desktop-test desktop-clean \
	release-assets-check release-assets-linux release-assets-windows release-assets-macos \
	_backend-lint _backend-test _backend-clean _backend-build \
	_versionctl-lint _versionctl-test \
	_frontend-install _frontend-build _frontend-check _frontend-test _frontend-dev _frontend-clean \
	_desktop-test _desktop-clean _desktop-prepare-frontend _desktop-prepare-embedfs _desktop-prepare-windows-resource \
	_server-run-backend _server-run-frontend

# Delay shell lookups until a target needs them, then cache the result for this make run.
lazy_shell = $(or $($(1)),$(eval $(1) := $(shell $(2)))$($(1)))

VERSION = $(call lazy_shell,_VERSION,go run ./versionctl print)
GIT_COMMIT ?= $(call lazy_shell,_GIT_COMMIT,git rev-parse --short HEAD 2>/dev/null || printf 'unknown')
BUILD_TIME ?= $(call lazy_shell,_BUILD_TIME,date -u +"%Y-%m-%dT%H:%M:%SZ")
GO_LDFLAGS = -X nex/backend/pkg/buildinfo.version=$(VERSION) -X nex/backend/pkg/buildinfo.commit=$(GIT_COMMIT) -X nex/backend/pkg/buildinfo.buildTime=$(BUILD_TIME)
GO_LDFLAGS_WIN = $(GO_LDFLAGS) -H=windowsgui
RELEASE_DIR := build/release
SERVER_LINUX_ASSET = $(call lazy_shell,_SERVER_LINUX_ASSET,go run ./versionctl asset-name server linux amd64)
SERVER_WINDOWS_ASSET = $(call lazy_shell,_SERVER_WINDOWS_ASSET,go run ./versionctl asset-name server windows amd64)
SERVER_DARWIN_AMD64_ASSET = $(call lazy_shell,_SERVER_DARWIN_AMD64_ASSET,go run ./versionctl asset-name server darwin amd64)
SERVER_DARWIN_ARM64_ASSET = $(call lazy_shell,_SERVER_DARWIN_ARM64_ASSET,go run ./versionctl asset-name server darwin arm64)
DESKTOP_LINUX_ASSET = $(call lazy_shell,_DESKTOP_LINUX_ASSET,go run ./versionctl asset-name desktop linux)
DESKTOP_WINDOWS_ASSET = $(call lazy_shell,_DESKTOP_WINDOWS_ASSET,go run ./versionctl asset-name desktop windows)
DESKTOP_MACOS_ASSET = $(call lazy_shell,_DESKTOP_MACOS_ASSET,go run ./versionctl asset-name desktop macos)

# ============================================
# 全局命令
# ============================================

lint: _backend-lint _frontend-check _versionctl-lint
	@printf 'Lint complete\n'

test: _backend-test _frontend-test _desktop-test _versionctl-test
	@printf 'All tests passed\n'

clean: _backend-clean _frontend-clean _desktop-clean
	@printf 'Clean complete\n'

# ============================================
# 版本管理
# ============================================

version-sync:
	go run ./versionctl sync

version-check:
	go run ./versionctl check

version-bump: BUMP ?= patch
version-bump:
	$(eval _BUMP_ARG := $(if $(SET_VERSION),$(SET_VERSION),$(BUMP)))
	$(eval _NEW_VERSION := $(shell go run ./versionctl bump $(_BUMP_ARG)))
	git add VERSION frontend/
	git commit -m "chore: 版本升迁 v$(_NEW_VERSION)"
	git tag "v$(_NEW_VERSION)"
	@printf '版本升迁完成: v%s\n' "$(_NEW_VERSION)"

# ============================================
# Server 模式
# ============================================

server-run:
	@$(MAKE) -j2 _server-run-backend _server-run-frontend

server-build: version-check _backend-build _frontend-build
	@printf 'Server build complete\n'

server-lint: _backend-lint _frontend-check
	@printf 'Server lint complete\n'

server-test: _backend-test _frontend-test
	@printf 'Server tests passed\n'

server-clean: _backend-clean _frontend-clean
	@printf 'Server artifacts cleaned\n'

_server-run-backend:
	@$(MAKE) -C backend run

_server-run-frontend: _frontend-install
	cd frontend && bun run dev

# ============================================
# Desktop 模式
# ============================================

desktop-build-mac: version-check _desktop-prepare-frontend _desktop-prepare-embedfs
	@printf 'Building macOS desktop...\n'
	cd backend && CGO_ENABLED=1 GOOS=darwin GOARCH=arm64 go build -ldflags "$(GO_LDFLAGS)" -o ../build/nex-mac-arm64 ./cmd/desktop
	cd backend && CGO_ENABLED=1 GOOS=darwin GOARCH=amd64 go build -ldflags "$(GO_LDFLAGS)" -o ../build/nex-mac-amd64 ./cmd/desktop
	lipo -create build/nex-mac-arm64 build/nex-mac-amd64 -output build/nex-mac-universal
	@printf 'Packaging macOS app bundle...\n'
	mkdir -p build/Nex.app/Contents/MacOS build/Nex.app/Contents/Resources
	cp build/nex-mac-universal build/Nex.app/Contents/MacOS/nex
	@if [ -f assets/icon.icns ]; then \
		cp assets/icon.icns build/Nex.app/Contents/Resources/; \
	else \
		printf 'Missing assets/icon.icns\n'; \
	fi
	@MIN_MACOS_VERSION=$$(vtool -show-build build/nex-mac-universal | awk '/minos / {print $$2; exit}'); \
	if [ -z "$$MIN_MACOS_VERSION" ]; then \
		printf 'Unable to read macOS minimum version\n'; \
		exit 1; \
	fi; \
	go run ./versionctl macos-plist "$$MIN_MACOS_VERSION" > build/Nex.app/Contents/Info.plist
	chmod +x build/Nex.app/Contents/MacOS/nex
	@printf 'macOS desktop build complete\n'

desktop-build-win: version-check _desktop-prepare-frontend _desktop-prepare-embedfs _desktop-prepare-windows-resource
	@printf 'Building Windows desktop...\n'
ifeq ($(OS),Windows_NT)
	powershell -NoProfile -Command "New-Item -ItemType Directory -Path 'build' -Force | Out-Null"
	cd backend && set "CGO_ENABLED=1"&& set "GOOS=windows"&& set "GOARCH=amd64"&& go build -ldflags "$(GO_LDFLAGS_WIN)" -o ../build/nex-win-amd64.exe ./cmd/desktop
else
	mkdir -p build
	cd backend && CGO_ENABLED=1 GOOS=windows GOARCH=amd64 go build -ldflags "$(GO_LDFLAGS_WIN)" -o ../build/nex-win-amd64.exe ./cmd/desktop
endif
	@printf 'Windows desktop build complete\n'

desktop-build-linux: version-check _desktop-prepare-frontend _desktop-prepare-embedfs
	@printf 'Building Linux desktop...\n'
	cd backend && CGO_ENABLED=1 GOOS=linux GOARCH=amd64 go build -ldflags "$(GO_LDFLAGS)" -o ../build/nex-linux-amd64 ./cmd/desktop
	@printf 'Linux desktop build complete\n'

desktop-lint: _backend-lint _frontend-check
	@printf 'Desktop lint complete\n'

desktop-test: _desktop-test
	@printf 'Desktop tests passed\n'

desktop-clean: _desktop-clean
	@printf 'Desktop artifacts cleaned\n'

_desktop-test:
	cd backend && go test ./cmd/desktop/... -v

_desktop-clean:
	rm -rf build/ embedfs/assets embedfs/frontend-dist backend/cmd/desktop/rsrc_windows_amd64.syso

_desktop-prepare-frontend: _frontend-install
	@printf 'Preparing frontend for desktop...\n'
ifeq ($(OS),Windows_NT)
	powershell -NoProfile -Command "Copy-Item -LiteralPath 'frontend/.env.desktop' -Destination 'frontend/.env.production.local' -Force"
	cd frontend && bun run build
	powershell -NoProfile -Command "Remove-Item -LiteralPath 'frontend/.env.production.local' -Force -ErrorAction SilentlyContinue"
else
	cd frontend && cp .env.desktop .env.production.local
	cd frontend && bun run build
	rm -f frontend/.env.production.local
endif

_desktop-prepare-embedfs:
	@printf 'Preparing embedded filesystem...\n'
ifeq ($(OS),Windows_NT)
	powershell -NoProfile -Command "Remove-Item -LiteralPath 'embedfs/assets' -Recurse -Force -ErrorAction SilentlyContinue; Remove-Item -LiteralPath 'embedfs/frontend-dist' -Recurse -Force -ErrorAction SilentlyContinue; Copy-Item -LiteralPath 'assets' -Destination 'embedfs/assets' -Recurse; Copy-Item -LiteralPath 'frontend/dist' -Destination 'embedfs/frontend-dist' -Recurse"
else
	rm -rf embedfs/assets embedfs/frontend-dist
	cp -r assets embedfs/assets
	cp -r frontend/dist embedfs/frontend-dist
endif

_desktop-prepare-windows-resource:
	@printf 'Preparing Windows executable icon...\n'
ifeq ($(OS),Windows_NT)
	cd backend/cmd/desktop && windres -O coff -F pe-x86-64 -i icon_windows.rc -o rsrc_windows_amd64.syso
else
	@if command -v x86_64-w64-mingw32-windres >/dev/null 2>&1; then \
		cd backend/cmd/desktop && x86_64-w64-mingw32-windres -O coff -F pe-x86-64 -i icon_windows.rc -o rsrc_windows_amd64.syso; \
	elif command -v windres >/dev/null 2>&1; then \
		cd backend/cmd/desktop && windres -O coff -F pe-x86-64 -i icon_windows.rc -o rsrc_windows_amd64.syso; \
	else \
		printf 'Missing windres for Windows icon resource generation\n'; \
		exit 1; \
	fi
endif

# ============================================
# 发布资产
# ============================================

release-assets-check:
	go run ./versionctl release-assets-check
	@printf 'Release assets check passed\n'

release-assets-linux: version-check release-assets-check desktop-build-linux
	rm -rf "$(RELEASE_DIR)"
	mkdir -p "$(RELEASE_DIR)"
	cd backend && CGO_ENABLED=1 GOOS=linux GOARCH=amd64 go build -ldflags "$(GO_LDFLAGS)" -o ../build/nex-server-linux-amd64 ./cmd/server
	tar -C build -czf "$(RELEASE_DIR)/$(SERVER_LINUX_ASSET)" nex-server-linux-amd64
	tar -C build -czf "$(RELEASE_DIR)/$(DESKTOP_LINUX_ASSET)" nex-linux-amd64

release-assets-windows: version-check release-assets-check desktop-build-win
ifeq ($(OS),Windows_NT)
	powershell -NoProfile -Command "Remove-Item -LiteralPath '$(RELEASE_DIR)' -Recurse -Force -ErrorAction SilentlyContinue; New-Item -ItemType Directory -Path '$(RELEASE_DIR)' -Force | Out-Null"
	cd backend && set "CGO_ENABLED=1"&& set "GOOS=windows"&& set "GOARCH=amd64"&& go build -ldflags "$(GO_LDFLAGS_WIN)" -o ../build/nex-server-win-amd64.exe ./cmd/server
	powershell -NoProfile -Command "Compress-Archive -LiteralPath 'build/nex-server-win-amd64.exe' -DestinationPath '$(RELEASE_DIR)/$(SERVER_WINDOWS_ASSET)' -Force"
	powershell -NoProfile -Command "Compress-Archive -LiteralPath 'build/nex-win-amd64.exe' -DestinationPath '$(RELEASE_DIR)/$(DESKTOP_WINDOWS_ASSET)' -Force"
else
	@printf 'release-assets-windows requires Windows\n'
	@exit 1
endif

release-assets-macos: version-check release-assets-check desktop-build-mac
	rm -rf "$(RELEASE_DIR)"
	mkdir -p "$(RELEASE_DIR)"
	cd backend && CGO_ENABLED=1 GOOS=darwin GOARCH=amd64 go build -ldflags "$(GO_LDFLAGS)" -o ../build/nex-server-darwin-amd64 ./cmd/server
	cd backend && CGO_ENABLED=1 GOOS=darwin GOARCH=arm64 go build -ldflags "$(GO_LDFLAGS)" -o ../build/nex-server-darwin-arm64 ./cmd/server
	tar -C build -czf "$(RELEASE_DIR)/$(SERVER_DARWIN_AMD64_ASSET)" nex-server-darwin-amd64
	tar -C build -czf "$(RELEASE_DIR)/$(SERVER_DARWIN_ARM64_ASSET)" nex-server-darwin-arm64
	ditto -c -k --keepParent build/Nex.app "$(RELEASE_DIR)/$(DESKTOP_MACOS_ASSET)"

# ============================================
# 共享 helper targets
# ============================================

_backend-build:
	@$(MAKE) -C backend build

_backend-lint:
	@$(MAKE) -C backend lint

_backend-test:
	@$(MAKE) -C backend test

_backend-clean:
	@$(MAKE) -C backend clean

_versionctl-lint:
	@$(MAKE) -C versionctl lint

_versionctl-test:
	@$(MAKE) -C versionctl test

_frontend-install:
	cd frontend && bun install

_frontend-build: _frontend-install
	cd frontend && bun run build

_frontend-check: _frontend-install
	cd frontend && bun run check

_frontend-test: _frontend-install
	cd frontend && bun run test

_frontend-dev: _frontend-install
	cd frontend && bun run dev

_frontend-clean:
	rm -rf frontend/dist frontend/.next frontend/coverage frontend/playwright-report frontend/test-results frontend/tsconfig.tsbuildinfo
