# Use bash
SHELL=/bin/bash

FLUTTER?=$(shell if which fvm &>/dev/null; then echo "fvm flutter"; else echo "flutter";fi) --suppress-analytics
DART?=$(shell if [ -x /Users/builder/programs/flutter/bin/dart ]; then echo "/Users/builder/programs/flutter/bin/dart"; elif which fvm &>/dev/null; then echo "fvm dart"; else echo "dart";fi) --disable-analytics
DART2JS?=$(DART) compile js
PUB?=$(FLUTTER) pub

# We use the total number of commits as build number. Google Play et.al. needs
# a continually increasing build number. Using the total number of commits is a
# bit stupid, but should work in most cases. In specific cases, you can provide
# BUILD_NO on the make command-line
COMMIT_NO:=$(shell git log --all --pretty=oneline|wc -l)
TAG_NO:=$(shell git tag -l |wc -l)
BUILD_NO?=$(shell perl -E 'say $(TAG_NO)+$(COMMIT_NO)')
BUILD_COMMIT:=$(shell git rev-parse --short=4 HEAD)
BUILD_VERSION:=$(shell grep version: pubspec.yaml |perl -p -E 's/^version:\s+//')
IOS_DEV_VERSION:= $(shell grep version: pubspec.yaml|perl -p -e 's/^\S+\s+//;s/\+\d+//; s/^(\d+)\.(\d+)\.?.*/$$1.$$2.$(BUILD_NO)/')
LINUX_BUILD_VERSION?=$(BUILD_VERSION)

ARGS_BUILDNO=--build-number=$(BUILD_NO)
ARGS_BUILDNAME?=
IOS_BUILD_ARGS?=
# Target platforms: all flutter supported platforms
TARGET_PLATFORM=android-arm,android-arm64,android-x64
# Used to limit which tests are run
TEST_LIMIT?=

JS_OPTIMIZE=-m

default: help

androidrelease: setRelVariant androiddistrib
	@make --no-print-directory setDevVariant
testRelease: _verifyForRelease test lint
_verifyForRelease:
	@if ! LC_ALL=C git status 2>&1|grep -iq "nothing to commit"; then echo "Commit changes first";exit 1;fi
	grep -q '[$(BUILD_VERSION)]' ChangeLog.md
	grep -q '[$(BUILD_VERSION)]' ChangeLog.no.md
	git fetch --tags
	! git tag |grep -q 'v$(BUILD_VERSION)'

# -- Linux --
buildlinux: _linux_compile
linuxrelease: setRelVariant _linux_compile
_linux_compile: prepare
	$(FLUTTER) build linux $(ARGS_BUILDNO) $(ARGS_BUILDNAME)
linuxtarball: _linux_clean linuxrelease _linux_tarball
_linux_clean:
	rm -rf build/linux/x64/release
_linux_tarball:
	cp ChangeLog*.md README.md COPYING.md build/linux/x64/release/bundle/
	perl -pi -E 's{"version":"[^\"]+"}{"version":"$(LINUX_BUILD_VERSION)"}g' build/linux/x64/release/bundle/data/flutter_assets/version.json
	cd build/linux/x64/release/ && mv bundle migrainelog-$(LINUX_BUILD_VERSION) && tar -Jcvf migrainelog-$(LINUX_BUILD_VERSION).x64.tar.xz migrainelog-$(LINUX_BUILD_VERSION) && mv migrainelog-$(LINUX_BUILD_VERSION).x64.tar.xz ../../../../
tarball:
	rm -fr ./migrainelog-$(BUILD_VERSION) ./migrainelog-$(BUILD_VERSION).tar.xz
	git clone ./ ./migrainelog-$(BUILD_VERSION)
	rm -rf ./migrainelog-$(BUILD_VERSION)/.git
	tar -Jcvf ./migrainelog-$(BUILD_VERSION).tar.xz ./migrainelog-$(BUILD_VERSION)

# -- Android --
androiddistrib: appbundleDistrib
appbundleDistrib: prepare
	$(FLUTTER) build appbundle --target-platform $(TARGET_PLATFORM) $(ARGS_BUILDNO) $(ARGS_BUILDNAME)
APK_EXTRA_PARAMS?=
apkdevel: APK_EXTRA_PARAMS=--debug
apkdevel: apkdistrib
apkdistrib: prepare
	$(FLUTTER) build apk --target-platform $(TARGET_PLATFORM) --split-per-abi $(ARGS_BUILDNO) $(ARGS_BUILDNAME) $(APK_EXTRA_PARAMS)
iosdistrib: prepare
	$(FLUTTER) build ipa $(IOS_BUILD_ARGS) $(ARGS_BUILDNO) $(ARGS_BUILDNAME)
fatapk: prepare _fdroidChangelogHack
	$(FLUTTER) build apk $(ARGS_BUILDNO) $(ARGS_BUILDNAME)
fatapk-install: fatapk
	adb install build/app/outputs/flutter-apk/app-release.apk
conditionalPrepare:
	@if [ ! -e assets/web.js ]; then make --no-print-directory prepare || exit 1;fi
	@for file in $$(ls i18n/*.arb|grep -v intl_messages.arb|perl -p -E 's/\.arb//; s/^i18n.//'); do\
		if [ ! -e lib/i18n/messages_$$file.dart ]; then\
			make --no-print-directory prepare || exit 1;\
		fi;\
	done
prepare: i18n-build jsBuild appStrings
appStrings:
	$(DART) ./scripts/buildLocalizedStrings
jsBuild: _jsBuild
	if which uglifyjs &>/dev/null; then\
		uglifyjs -c -m -o assets/web.js.out -- assets/web.js;\
		mv assets/web.js.out assets/web.js;\
	fi
_jsBuild:
	mkdir -p assets
	$(DART2JS) $(JS_OPTIMIZE) lib/web.dart -o assets/web.js
jsDebug: JS_OPTIMIZE=
jsDebug: _jsBuild
I18N_LANG_FILES=$$(ls ./i18n/*.arb|\grep -E -v '/(intl_messages|en)'.arb)
i18n-extract: _initialize
	mkdir -p i18n
	$(PUB) run intl_translation:extract_to_arb --output-dir=./i18n/ lib/*.dart
	for arb in $(I18N_LANG_FILES); do\
		$(DART) ./scripts/arbtool merge ./i18n/intl_messages.arb "$$arb";\
	done
	@make -C i18n stats
i18n-build: _initialize
	mkdir -p i18n
	mkdir -p lib/i18n
	$(PUB) run intl_translation:generate_from_arb --output-dir=lib/i18n/ lib/*.dart $(I18N_LANG_FILES)
i18n-test:
	$(FLUTTER) test test/i18n_test.dart
format: _initialize
	$(DART) format ./lib/
distTest: test lint
_testPrep: _initialize conditionalPrepare
test: _testPrep testFlutter webTest
testFlutter: _testPrep
	$(FLUTTER) test $(TEST_LIMIT)
webTest: _testPrep
	$(PUB) run test --platform chrome test/web_test.dart
updateGoldens: _initialize
	$(FLUTTER) test --update-goldens
SCREENSHOT_LANGUAGES?=en-GB fi-FI no-NO es-ES de-DE zh-CN fr-FR eu-ES
screenshots: prepare
	if [ "$(shell uname -s)" == "Darwin" ]; then make --no-print-directory screenshots_ios; else make --no-print-directory screenshots_android;fi
screenshots_android:
	for locale in $(SCREENSHOT_LANGUAGES); do\
		mkdir -p android/fastlane/metadata/android/$$locale/images/phoneScreenshots;\
		$(DART) ./scripts/prepareForScreenshots "$$locale" || exit 1;\
		$(FLUTTER) drive --target=test_driver/screenshots-built.dart || exit 1;\
		no=0;for file in ss*png; do\
			let no=$$no+1;\
			dir="android/fastlane/metadata/android/$$locale/images/phoneScreenshots";\
			composite -gravity NorthEast android/fastlane/overlay-top.png "$$file" "$$dir/$$no.png" || exit 1;\
			rm -f "$$file"; \
		done;\
	done
	rm -f ./test_driver/*-built*dart
screenshots_ios:
	bash ios/take-ios-screenshots
screenshots_ios_snapshot:
	xcrun simctl status_bar booted override --time '9:41' --batteryState charged --batteryLevel 100 --cellularMode active --cellularBars 4 --wifiMode active --wifiBars 3
	for locale in $(SCREENSHOT_LANGUAGES); do\
		mkdir -p ios-screenshots/$$locale/;\
		$(DART) ./scripts/prepareForScreenshots "$$locale" || exit 1;\
		$(FLUTTER) drive --target=test_driver/screenshots-built.dart || exit 1;\
		no=0;for file in ss*png; do\
			let no=$$no+1;\
			dir="ios-screenshots/$$locale/";\
			mv "$$file" "$$dir/$$no.png" || exit 1;\
		done;\
	done
	rm -f ./test_driver/*-built*dart

ONCHANGETEST_TARGET?=test
onChangeTestWeb: ONCHANGETEST_TARGET=webTest
onChangeTestWeb: onChangeTest
onChangeTest:
onChangeTest:
	while :;do echo ""; echo -n "$$(date +'[%H:%M:%S]') "; make --no-print-directory $(ONCHANGETEST_TARGET) TEST_LIMIT="$(TEST_LIMIT)";inotifywait -qq -e close,move,create test lib;done
onChangeWeb:
	while :;do echo ""; echo -n "$$(date +'[%H:%M:%S]') "; make --no-print-directory jsDebug; if [ -e "migrainelog.html" ]; then perl scripts/patch-export.pl migrainelog.html;fi;inotifywait -qq -e close,move,create test lib;done
# This runs the tests 20 times in random order. If we've messed up some async
# code and added a race condition, it's likely that this will detect that and
# randomly fail.
asyncTestRunner: _testPrep
	n=0; while [ "$$n" -lt "10" ]; do let n=$$n+1;$(FLUTTER) test --test-randomize-ordering-seed=random || exit 1;done
distTest: test
	$(FLUTTER) test --test-randomize-ordering-seed=random
lint: _initialize
	$(DART) analyze --fatal-infos
# Builds our test coverage information. Tests that are labelled
# "skip-test-coverage" are excluded when generating coverage. See
# dart_test.yaml for details.
testCoverage:
	$(FLUTTER) test --exclude-tags skip-test-coverage --coverage
	lcov -r coverage/lcov.info 'lib/i18n/*' -o coverage/new
	mv coverage/new coverage/lcov.info
	genhtml coverage/lcov.info -o coverage/html
	lcov -l coverage/lcov.info

.PHONY: build test
build:
	@echo "Generated build number: $(BUILD_NO)"
	@echo "Generated dev release version: $(BUILD_COMMIT)"
	@echo "Generated ios dev release version: $(IOS_DEV_VERSION)"
	@echo "Actual version: $(shell grep version: pubspec.yaml|perl -p -e 's/^\S+\s+//;s/\+\d+//')"

clean:
	rm -rf build \
		test/failures \
		test_driver/screenshots-built*dart \
		./android/fastlane/metadata/android/*/changelogs/
	rm -f migrainelog-*.tar.xz
distclean: clean
	rm -rf assets/web* \
		lib/i18n
_initialize:
	@if [ -d "./.git/hooks" ]; then ln -sf "$(shell pwd)/scripts/pre-push" .git/hooks/pre-push; fi

prePush: _initialize distTest
	! egrep -q 'print\s*\(' lib/*dart

help:
	@echo "Platform: Linux"
	@echo "buildlinux          - Build development variant for Linux"
	@echo "linuxrelease        - Build release variant for Linux"
	@echo "";echo "Platform: Android"
	@echo "androiddistrib      - Build aap"
	@echo "androidrelease      - Build release aap"
	@echo "apkdistrib          - Build release apk"
	@echo "";echo "Platform: iOS"
	@echo "iosdistrib          - Build for iOS"
	@echo ""; echo "Other"
	@echo "tarball             - Build a source tarball"
	@echo "setRelVariant       - Switch to 'release' app namespace"
	@echo "setDevVariant       - Switch to development app namespace"
	@echo "i18n-build          - Build i18n .dart files"
	@echo "i18n-extract        - Extract i18n strings and update files in i18n/"
	@echo "jsBuild             - Compile the javascript component (for exported html)"
	@echo "test                - Run both flutter and web tests (requires chrome)"
	@echo "testFlutter         - Run flutter app tests"
	@echo "webTest             - Run web (export) tests (requires chrome)"

ciPrep:
	$(PUB) get
ciApkDist: ciPrep setRelVariant apkdistrib fatapk
ciAppbundleDist: ciPrep setRelVariant appbundleDistrib
fastlaneCIPrep:
	rm -f android/fastlane/metadata/android/nb-NO android/fastlane/metadata/android/nn-NO

# Note that AppbundleDev builds with the package name org.zerodogg.migraineLog,
# while ApkDev builds with or.zerodogg.migraineLogTest.
ciAppbundleDev: ARGS_BUILDNAME=--build-name=$(BUILD_COMMIT)
ciAppbundleDev: ciAppbundleDist
ciApkDev: ARGS_BUILDNAME=--build-name=$(BUILD_COMMIT)
ciApkDev: ciPrep setDevVariant setTestName apkdistrib fatapk

DEVHACK_FILES=android/app/build.gradle android/app/src/debug/AndroidManifest.xml android/app/src/profile/AndroidManifest.xml android/app/src/main/AndroidManifest.xml android/app/src/main/kotlin/com/example/MigraineLog/MainActivity.kt
setRelVariant:
	perl -pi -e 's{org.zerodogg.migraineLog(Test)?}{org.zerodogg.migraineLog}' $(DEVHACK_FILES)
	-git update-index --assume-unchanged $(DEVHACK_FILES)
setDevVariant:
	perl -pi -e 's{org.zerodogg.migraineLog(Test)?}{org.zerodogg.migraineLogTest}' $(DEVHACK_FILES)
	-git update-index --no-assume-unchanged $(DEVHACK_FILES)
setTestName:
	perl -pi -e 's{<string name="app_name">([^<]+)</string>}{<string name="app_name">$$1 (test)</string>}' android/app/src/main/res/values*/strings.xml

ciAsyncTest: ciPrep prepare testCoverage asyncTestRunner
ciTest: ciPrep prepare test lint
	@make --no-print-directory -C i18n stats

ciIOSdev: ARGS_BUILDNAME=--build-name=$(IOS_DEV_VERSION)
ciIOSdev: IOS_BUILD_ARGS=--export-options-plist=/Users/builder/export_options.plist
ciIOSdev: ciPrep iosdistrib

ciIOSrelease: IOS_BUILD_ARGS=--release --export-options-plist=/Users/builder/export_options.plist
ciIOSrelease: ciPrep iosdistrib


ciLinuxDev: ARGS_BUILDNO=--build-name=$(BUILD_COMMIT)
ciLinuxDev: LINUX_BUILD_VERSION=git-$(BUILD_COMMIT)
ciLinuxDev: ciPrep _linux_clean _linux_compile _linux_tarball
ciLinuxRelease: ciPrep setRelVariant _linux_clean _linux_compile _linux_tarball tarball

ciUploadSnapshot: PKGBUILDVERSION=$(shell date '+%Y.%m.%d')
ciUploadSnapshot: PKGRELVERSION=$(BUILD_NO)-$(PKGBUILDVERSION)-$(BUILD_COMMIT)
ciUploadSnapshot: PKGBUILDTARGET=snapshot
ciUploadSnapshot: _ciUpload
ciUploadRelease: PKGBUILDVERSION=$(shell grep version: pubspec.yaml | perl -p -e 's/^\S+\s+//;s/\+\d+//;s/\s//g')#'
ciUploadRelease: PKGRELVERSION=$(PKGBUILDVERSION)
ciUploadRelease: PKGBUILDTARGET=release
ciUploadRelease: _ciUpload
_ciUpload:
	for file in build/app/outputs/flutter-apk/app-arm64-v8a-release.apk build/app/outputs/flutter-apk/app-x86_64-release.apk build/app/outputs/flutter-apk/app-armeabi-v7a-release.apk build/app/outputs/flutter-apk/app-release.apk *.tar.xz; do\
		name="$$(basename "$$file"|perl -p -E 's/^app-release.apk/app-release-fat.apk/;s/^app/migrainelog-$(PKGRELVERSION)/; s/-release//g')";\
		curl --header "JOB-TOKEN: $$CI_JOB_TOKEN" --upload-file "$$file" "$${CI_API_V4_URL}/projects/$${CI_PROJECT_ID}/packages/generic/$(PKGBUILDTARGET)/$(PKGBUILDVERSION)/$$name";\
	done

fdroid: _fdroidChangelogHack appStrings setRelVariant fatapk
	@echo "Note: current variant is set to org.zerodogg.migraineLog"
_fdroidChangelogHack:
	mkdir -p ./android/fastlane/metadata/android/en-GB/changelogs/ ./android/fastlane/metadata/android/no-NO/changelogs/
	cat ChangeLog.md|perl -E 'my $$first = 1;my $$seen = 0; while(<>) { if($$seen) { last if /^\#\#\s+/; if ($$first) { $$first = 0; next;} s/^\#\#\#\s+//; print $$_; } else { $$seen = /^\#\# \[\d/; } }' > ./android/fastlane/metadata/android/en-GB/changelogs/"$(BUILD_NO)".txt
	cat ChangeLog.no.md|perl -E 'my $$first = 1;my $$seen = 0; while(<>) { if($$seen) { last if /^\#\#\s+/; if ($$first) { $$first = 0; next;} s/^\#\#\#\s+//; print $$_; } else { $$seen = /^\#\# \[\d/; } }' > ./android/fastlane/metadata/android/no-NO/changelogs/"$(BUILD_NO)".txt

fdroidYaml:
	mkdir -p public/
	echo "version: $(BUILD_VERSION)" > public/latest.yml
	echo "versionCode: $(BUILD_NO)" >> public/latest.yml
	echo "combined: $(BUILD_VERSION)+$(BUILD_NO)" >> public/latest.yml
	echo '<!DOCTYPE html><html><head><title>Migraine Log</title></head><body><a href="https://gitlab.com/mglog/org.zerodogg.migraineLog/">Repository</a></body></html>' >> public/index.html
