help:
	@sed \
		-e '/^[a-zA-Z0-9_\-]*:.*##/!d' \
		-e 's/:.*##\s*/:/' \
		-e 's/^\(.\+\):\(.*\)/$(shell tput setaf 6)\1$(shell tput sgr0):\2/' \
		$(MAKEFILE_LIST) | column -c2 -t -s :

DOCKER_COMPOSE_FILE = docker-compose-developer.yml
DOCKER_COMPOSE_DEV_LABEL = com.grafana.oncall.env=dev

# compose profiles
MYSQL_PROFILE = mysql
POSTGRES_PROFILE = postgres
SQLITE_PROFILE = sqlite
ENGINE_PROFILE = engine
UI_PROFILE = oncall_ui
REDIS_PROFILE = redis
RABBITMQ_PROFILE = rabbitmq
PROMETHEUS_PROFILE = prometheus
GRAFANA_PROFILE = grafana

DEV_ENV_DIR = ./dev
DEV_ENV_FILE = $(DEV_ENV_DIR)/.env.dev
DEV_ENV_EXAMPLE_FILE = $(DEV_ENV_FILE).example

ENGINE_DIR = ./engine
REQUIREMENTS_TXT = $(ENGINE_DIR)/requirements.txt
REQUIREMENTS_ENTERPRISE_TXT = $(ENGINE_DIR)/requirements-enterprise.txt
SQLITE_DB_FILE = $(ENGINE_DIR)/oncall.db

# -n flag only copies DEV_ENV_EXAMPLE_FILE-> DEV_ENV_FILE if it doesn't already exist
$(shell cp -n $(DEV_ENV_EXAMPLE_FILE) $(DEV_ENV_FILE))
include $(DEV_ENV_FILE)

# if COMPOSE_PROFILES is set in DEV_ENV_FILE use it
# otherwise use a default (or what is passed in as an arg)
ifeq ($(COMPOSE_PROFILES),)
	COMPOSE_PROFILES=$(ENGINE_PROFILE),$(UI_PROFILE),$(REDIS_PROFILE),$(GRAFANA_PROFILE)
endif

# conditionally assign DB based on what is present in COMPOSE_PROFILES
ifeq ($(findstring $(MYSQL_PROFILE),$(COMPOSE_PROFILES)),$(MYSQL_PROFILE))
	DB=$(MYSQL_PROFILE)
else ifeq ($(findstring $(POSTGRES_PROFILE),$(COMPOSE_PROFILES)),$(POSTGRES_PROFILE))
	DB=$(POSTGRES_PROFILE)
else
	DB=$(SQLITE_PROFILE)
endif

# conditionally assign BROKER_TYPE based on what is present in COMPOSE_PROFILES
# if the user specifies both rabbitmq and redis, we'll make the assumption that rabbitmq is the broker
ifeq ($(findstring $(RABBITMQ_PROFILE),$(COMPOSE_PROFILES)),$(RABBITMQ_PROFILE))
	BROKER_TYPE=$(RABBITMQ_PROFILE)
else
	BROKER_TYPE=$(REDIS_PROFILE)
endif

# SQLITE_DB_FiLE is set to properly mount the sqlite db file
DOCKER_COMPOSE_ENV_VARS := COMPOSE_PROFILES=$(COMPOSE_PROFILES) DB=$(DB) BROKER_TYPE=$(BROKER_TYPE)
ifeq ($(DB),$(SQLITE_PROFILE))
	DOCKER_COMPOSE_ENV_VARS += SQLITE_DB_FILE=$(SQLITE_DB_FILE)
endif

define run_docker_compose_command
	$(DOCKER_COMPOSE_ENV_VARS) docker compose -f $(DOCKER_COMPOSE_FILE) $(1)
endef

define run_engine_docker_command
	$(call run_docker_compose_command,run --rm oncall_engine_commands $(1))
endef

define run_ui_docker_command
	$(call run_docker_compose_command,run --rm oncall_ui sh -c '$(1)')
endef

# touch SQLITE_DB_FILE if it does not exist and DB is eqaul to SQLITE_PROFILE
start:  ## start all of the docker containers
ifeq ($(DB),$(SQLITE_PROFILE))
	@if [ ! -f $(SQLITE_DB_FILE) ]; then \
		touch $(SQLITE_DB_FILE); \
	fi
endif

	$(call run_docker_compose_command,up --remove-orphans -d)

init:  ## build the frontend plugin code then run make start
# if the oncall UI is to be run in docker we should do an initial build of the frontend code
# this makes sure that it will be available when the grafana container starts up without the need to
# restart the grafana container initially
ifeq ($(findstring $(UI_PROFILE),$(COMPOSE_PROFILES)),$(UI_PROFILE))
	$(call run_ui_docker_command,yarn install && yarn build:dev)
endif

stop:  # stop all of the docker containers
	$(call run_docker_compose_command,down)

restart:  ## restart all docker containers
	$(call run_docker_compose_command,restart)

build:  ## rebuild images (e.g. when changing requirements.txt)
	$(call run_docker_compose_command,build)

cleanup: stop  ## this will remove all of the images, containers, volumes, and networks
               ## associated with your local OnCall developer setup
	docker system prune --filter label="$(DOCKER_COMPOSE_DEV_LABEL)" --all --volumes

install-pre-commit:
	@if [ ! -x "$$(command -v pre-commit)" ]; then \
		echo "installing pre-commit"; \
		pip install $$(grep "pre-commit" $(ENGINE_DIR)/requirements.txt); \
	else \
		echo "pre-commit already installed"; \
	fi

lint: install-pre-commit  ## run both frontend and backend linters
                          ## may need to run `yarn install` from within `grafana-plugin`
                          ## to install several `pre-commit` dependencies

	pre-commit run --all-files

install-precommit-hook: install-pre-commit
	pre-commit install

test:  ## run backend tests
# always use settings.ci-test django settings file when running the tests
# if we use settings.dev it's very possible that some fail just based on the settings alone
	$(call run_engine_docker_command,pytest --ds=settings.ci-test)

start-celery-beat:  ## start celery beat
	$(call run_engine_docker_command,celery -A engine beat -l info)

purge-queues: ## purge celery queues
	$(call run_engine_docker_command,celery -A engine purge -f)

shell:  ## starts an OnCall engine Django shell
	$(call run_engine_docker_command,python manage.py shell)

dbshell:  ## opens a DB shell
	$(call run_engine_docker_command,python manage.py dbshell)

engine-manage:  ## run Django's `manage.py` script, inside of a docker container, passing `$CMD` as arguments.
                ## e.g. `make engine-manage CMD="makemigrations"`
                ## https://docs.djangoproject.com/en/4.1/ref/django-admin/#django-admin-makemigrations
	$(call run_engine_docker_command,python manage.py $(CMD))

ui-test:  ## run the UI tests
	$(call run_ui_docker_command,yarn test)

ui-lint:  ## run the UI linter
	$(call run_ui_docker_command,yarn lint)

ui-build:  ## build the UI
	$(call run_ui_docker_command,yarn build)

ui-command:  ## run any command, inside of a UI docker container, passing `$CMD` as arguments.
             ## e.g. `make ui-command CMD="yarn test"`
	$(call run_ui_docker_command,$(CMD))

exec-engine:  ## exec into engine container's bash
	docker exec -it oncall_engine bash

_backend-debug-enable:  ## enable Django's debug mode and Silk profiling (this is disabled by default for performance reasons)
	$(shell ./dev/add_env_var.sh DEBUG True $(DEV_ENV_FILE))
	$(shell ./dev/add_env_var.sh SILK_PROFILER_ENABLED True $(DEV_ENV_FILE))

_backend-debug-disable:  ## disable Django's debug mode and Silk profiling
	$(shell ./dev/add_env_var.sh DEBUG False $(DEV_ENV_FILE))
	$(shell ./dev/add_env_var.sh SILK_PROFILER_ENABLED False $(DEV_ENV_FILE))

backend-debug-enable: _backend-debug-enable stop start
backend-debug-disable: _backend-debug-disable stop start

# The below commands are useful for running backend services outside of docker
define backend_command
	export `grep -v '^#' $(DEV_ENV_FILE) | xargs -0` && \
	export BROKER_TYPE=$(BROKER_TYPE) && \
	cd engine && \
	$(1)
endef

backend-bootstrap:
	pip install -U pip wheel
	pip install -r $(REQUIREMENTS_TXT)
	@if [ -f $(REQUIREMENTS_ENTERPRISE_TXT) ]; then \
		pip install -r $(REQUIREMENTS_ENTERPRISE_TXT); \
	fi

backend-migrate:
	$(call backend_command,python manage.py migrate)

run-backend-server:
	$(call backend_command,python manage.py runserver 0.0.0.0:8080)

run-backend-celery:
	$(call backend_command,python manage.py start_celery)

backend-command:
	$(call backend_command,$(CMD))

backend-manage-command:  ## run Django's `manage.py` script, passing `$CMD` as arguments.
                         ## e.g. `make backend-manage-command CMD="makemigrations"`
                         ## https://docs.djangoproject.com/en/4.1/ref/django-admin/#django-admin-makemigrations
                         ## alternatively you can open docker container with engine and run commands from there
	$(call backend_command,python manage.py $(CMD))
