# GNU Make 3.81+; no extra application dependencies or automatic downloads.
.DEFAULT_GOAL := help
.DELETE_ON_ERROR:

GO ?= go
GOFMT ?= gofmt
NODE ?= node
PYTHON ?= python3
PORT ?= 8765
BROWSER ?= chromium
BUILD_DIR ?= build
PUBLIC_DIR ?= dist/soffice
PUBLIC_CONFIG ?= deploy/configs/simon-waldherr.yaml
PUBLIC_ARGS ?=
DATA_DIR ?= .office-data
SERVER_ARGS ?=
TEST_ARGS ?=
JS_TEST_ARGS ?=
BOOTSTRAP_ARGS ?=
GOCACHE ?= $(abspath .build/go-cache)
export GOCACHE BROWSER

# Upstream source snapshots are intentionally excluded from ordinary formatting.
GO_SOURCES := $(wildcard *.go) $(shell find cmd -type f -name '*.go')
BROWSER_SUITES := browser i18n themes workspace local-backup code media formats compatibility server enterprise accounts admin sessions account-settings collaboration ot-opt-in exclusive-editors room-management shares shared-editors office office-export interchange public presentation browser-data ui-render
BROWSER_FILE_browser := browser
BROWSER_FILE_browser-data := browser_data_browser
BROWSER_FILE_ui-render := ui_render
BROWSER_FILE_ot-opt-in := collaboration_opt_in_browser

.PHONY: help dev dev-backend assets source-defaults build public wasm tinyot \
        fmt fmt-check fmt-tinyot check lint check-js check-python vet test test-fast \
        test-js test-go test-tinyot test-race verify test-browser \
        test-browser-wasm test-browser-public test-browser-all test-browser-matrix clean FORCE

help: ## Show common commands and configuration
	@printf '%s\n' 'SovereignOffice development' ''
	@awk 'BEGIN {FS = ":.*## "} /^[a-zA-Z0-9_-]+:.*## / {printf "  %-24s %s\n", $$1, $$2}' $(MAKEFILE_LIST)
	@printf '%s\n' '' 'Configuration: PYTHON, GO, NODE, PORT, BROWSER, CHROMIUM_PATH,' '  GOCACHE, TEST_ARGS, JS_TEST_ARGS, SERVER_ARGS, DATA_DIR, PUBLIC_DIR.' '' 'Individual browser suites: make test-browser-<name>' '  $(BROWSER_SUITES)' '' 'No target uploads or publishes anything.'

dev: assets ## Start the local frontend; edit files and refresh the browser
	PORT="$(PORT)" $(NODE) tools/serve.mjs

dev-backend: assets ## Start private accounts/backend; requires SOVEREIGN_PASSWORD
	$(GO) run ./cmd/sovereign -port "$(PORT)" -open=false -data-dir "$(DATA_DIR)" -accounts $(SERVER_ARGS)

assets: ## Refresh offline assets for the locally installed runtimes
	$(PYTHON) tools/build.py

source-defaults: ## Prepare versioned offline metadata for a fresh source checkout
	$(PYTHON) tools/build.py --source-defaults

build: assets ## Build the Go launcher with current embedded assets
	@mkdir -p "$(BUILD_DIR)"
	$(GO) build -trimpath -o "$(BUILD_DIR)/sovereignoffice" ./cmd/sovereign

public: ## Build the static public package locally (uses bundled tinySQL)
	$(PYTHON) tools/build_public.py --config "$(PUBLIC_CONFIG)" --output "$(PUBLIC_DIR)" $(PUBLIC_ARGS)

wasm: ## Explicitly build tinySQL; may download the pinned upstream/toolchain
	$(PYTHON) tools/bootstrap.py --wasm $(BOOTSTRAP_ARGS)

tinyot: ## Rebuild local tinyOT WASM and its source/asset hashes
	$(PYTHON) tools/build_tinyot.py

fmt: ## Format application Go source using gofmt
	$(GOFMT) -w $(GO_SOURCES)

fmt-check: ## Fail if application Go source needs formatting
	@set -e; files="$$($(GOFMT) -l $(GO_SOURCES))"; if [ -n "$$files" ]; then printf '%s\n' "$$files"; printf '%s\n' 'Run make fmt.'; exit 1; fi

fmt-tinyot: ## Explicitly format the local tinyOT snapshot and rebuild if changed
	@set -e; files="$$(find third_party/tinyOT -type f -name '*.go' -exec $(GOFMT) -l {} +)"; if [ -n "$$files" ]; then printf '%s\n' "$$files"; find third_party/tinyOT -type f -name '*.go' -exec $(GOFMT) -w {} +; $(PYTHON) tools/build_tinyot.py; fi

check: fmt-check check-js check-python vet ## Check formatting, JS/imports/hashes, Python syntax and Go vet

lint: check ## Alias for all static checks

check-js:
	$(NODE) tools/check.mjs

check-python:
	$(PYTHON) -c 'import ast,pathlib; files=sorted([*pathlib.Path("tools").glob("*.py"),*pathlib.Path("tests").glob("*.py")]); [ast.parse(p.read_text(encoding="utf-8"),filename=str(p)) for p in files]; print(str(len(files))+" Python files checked.")'

vet: ## Run Go vet for the application and local tinyOT module
	$(GO) vet ./...
	cd third_party/tinyOT && $(GO) vet ./...

test-fast: test-js ## Fast feedback: all JS unit tests (no browser/WASM rebuild)

test: test-public-config test-js test-go test-tinyot ## Run JS and both Go module test suites

test-js:
	$(NODE) --test $(JS_TEST_ARGS) tests/*.test.mjs

test-go:
	$(GO) test $(TEST_ARGS) ./...

test-tinyot:
	cd third_party/tinyOT && $(GO) test $(TEST_ARGS) ./...

test-race: ## Run both Go suites with the race detector
	$(GO) test -race $(TEST_ARGS) ./...
	cd third_party/tinyOT && $(GO) test -race $(TEST_ARGS) ./...

verify: check test ## Complete non-browser verification

test-browser: ## Smoke test real storage, file roundtrip and offline use
	$(PYTHON) tests/browser.py

test-browser-wasm: ## Smoke test with real tinySQL execution/rollback; uses bundled tinySQL
	$(PYTHON) tests/browser.py --wasm

test-browser-public: public ## Test the generated public package with all nine tools
	PUBLIC_DIR="$(abspath $(PUBLIC_DIR))" $(PYTHON) tests/public_browser.py

# Keep browser batches sequential: suites regenerate shared offline metadata.
test-browser-all: ## Run all browser suites sequentially in BROWSER
	@set -e; for suite in $(BROWSER_SUITES); do $(MAKE) test-browser-$$suite; done

test-browser-matrix: ## Run all suites sequentially in Chromium, Firefox and WebKit
	@set -e; for browser in chromium firefox webkit; do $(MAKE) test-browser-all BROWSER=$$browser; done

test-browser-%: FORCE
	$(PYTHON) tests/$(if $(BROWSER_FILE_$*),$(BROWSER_FILE_$*),$(subst -,_,$*)_browser).py

FORCE:

clean: ## Remove only the native launcher; retain documents, runtimes and caches
	rm -f "$(BUILD_DIR)/sovereignoffice"

.PHONY: test-public-config
test-public-config: ## Validate public YAML profiles and legal page rendering
	$(PYTHON) tests/public_config_test.py
