SHELL := /bin/bash
.ONESHELL:
.SHELLFLAGS := -eu -o pipefail -c
.DELETE_ON_ERROR:

PYTHON_COMMAND := uv run python

# --- Paths
PROTO_DEPS := ./proto-deps
COSMOS_SDK_DIR := $(PROTO_DEPS)/cosmos-sdk
COSMOS_PROTO_DIR := $(PROTO_DEPS)/cosmos-proto
FEEMARKET_DIR := $(PROTO_DEPS)/feemarket
GOGOPROTO_DIR := $(PROTO_DEPS)/gogoproto
GOOGLEAPIS_DIR := $(PROTO_DEPS)/googleapis
ALLORA_CHAIN_DIR := $(PROTO_DEPS)/allora-chain

ALLORA_PROTOS_DIR := ./src/allora_sdk/rpc_client/protos
INTERFACE_OUT_DIR := ./src/allora_sdk/rpc_client/interfaces
REST_CLIENT_OUT_DIR := ./src/allora_sdk/rpc_client/rest
GRPC_WRAPPER_OUT_DIR := ./src/allora_sdk/rpc_client/grpc

# --- Stamps (single-file "products" for multi-file gens)
PROTO_STAMP := $(ALLORA_PROTOS_DIR)/.generated.stamp
INTERFACE_STAMP := $(INTERFACE_OUT_DIR)/.generated.stamp
REST_STAMP  := $(REST_CLIENT_OUT_DIR)/.generated.stamp
GRPC_STAMP  := $(GRPC_WRAPPER_OUT_DIR)/.generated.stamp

# --- Default
.PHONY: dev
dev: install_as_editable codegen
	@echo "✅ Ready for development."

.PHONY: install_as_editable
install_as_editable:
	uv pip install -e ".[dev]" ".[codegen]"

.PHONY: codegen
codegen: $(PROTO_STAMP) $(INTERFACE_STAMP) $(REST_STAMP) $(GRPC_STAMP)

.PHONY: wheel
wheel:
	uv build

# --- Git dependencies
$(GOGOPROTO_DIR)/.git:
	rm -rf "$(GOGOPROTO_DIR)"
	git clone --depth 1 --single-branch --branch v1.7.0 \
	  https://github.com/cosmos/gogoproto "$(GOGOPROTO_DIR)"

$(COSMOS_PROTO_DIR)/.git:
	rm -rf "$(COSMOS_PROTO_DIR)"
	git clone --depth 1 --single-branch --branch v1.0.0-beta.5 \
	  https://github.com/cosmos/cosmos-proto "$(COSMOS_PROTO_DIR)"

$(COSMOS_SDK_DIR)/.git:
	rm -rf "$(COSMOS_SDK_DIR)"
	git clone --depth 1 --single-branch --branch v0.50.13 \
	  https://github.com/cosmos/cosmos-sdk "$(COSMOS_SDK_DIR)"

$(FEEMARKET_DIR)/.git:
	rm -rf "$(FEEMARKET_DIR)"
	git clone --depth 1 --single-branch --branch v1.1.1 \
	  https://github.com/skip-mev/feemarket "$(FEEMARKET_DIR)"

$(GOOGLEAPIS_DIR)/.git:
	rm -rf "$(GOOGLEAPIS_DIR)"
	git clone --depth 1 --single-branch --branch master \
	  https://github.com/googleapis/googleapis "$(GOOGLEAPIS_DIR)"

$(ALLORA_CHAIN_DIR)/.git:
	rm -rf "$(ALLORA_CHAIN_DIR)"
	git clone --depth 1 --single-branch --branch v0.17.0 \
	  https://github.com/allora-network/allora-chain "$(ALLORA_CHAIN_DIR)"

.PHONY: proto-deps
proto-deps: \
  $(GOGOPROTO_DIR)/.git \
  $(COSMOS_PROTO_DIR)/.git \
  $(COSMOS_SDK_DIR)/.git \
  $(FEEMARKET_DIR)/.git \
  $(GOOGLEAPIS_DIR)/.git \
  $(ALLORA_CHAIN_DIR)/.git

.PHONY: proto-deps-update
proto-deps-update:
	git -C "$(GOGOPROTO_DIR)" fetch --depth 1 origin v1.7.0 && git -C "$(GOGOPROTO_DIR)" reset --hard FETCH_HEAD
	git -C "$(COSMOS_PROTO_DIR)" fetch --depth 1 origin v1.0.0-beta.5 && git -C "$(COSMOS_PROTO_DIR)" reset --hard FETCH_HEAD
	git -C "$(COSMOS_SDK_DIR)" fetch --depth 1 origin v0.50.13 && git -C "$(COSMOS_SDK_DIR)" reset --hard FETCH_HEAD
	git -C "$(FEEMARKET_DIR)" fetch --depth 1 origin v1.1.1 && git -C "$(FEEMARKET_DIR)" reset --hard FETCH_HEAD
	git -C "$(GOOGLEAPIS_DIR)" fetch --depth 1 origin master && git -C "$(GOOGLEAPIS_DIR)" reset --hard FETCH_HEAD
	git -C "$(ALLORA_CHAIN_DIR)" fetch --depth 1 origin v0.17.0 && git -C "$(ALLORA_CHAIN_DIR)" reset --hard FETCH_HEAD

# --- Ensure output dirs exist (order-only)
$(ALLORA_PROTOS_DIR):
	mkdir -p "$@"

$(INTERFACE_OUT_DIR):
	mkdir -p "$@"

$(REST_CLIENT_OUT_DIR):
	mkdir -p "$@"

$(GRPC_WRAPPER_OUT_DIR):
	mkdir -p "$@"

# --- Protobuf generation (stamp depends on repos + generator + Makefile)
$(PROTO_STAMP): \
  $(ALLORA_CHAIN_DIR)/.git \
  $(COSMOS_SDK_DIR)/.git \
  $(COSMOS_PROTO_DIR)/.git \
  $(FEEMARKET_DIR)/.git \
  $(GOOGLEAPIS_DIR)/.git \
  $(GOGOPROTO_DIR)/.git \
  $(PROTO_INIT_TEMPLATE) \
  Makefile \
  | $(ALLORA_PROTOS_DIR)
	rm -rf "$(ALLORA_PROTOS_DIR)"
	mkdir -p "$(ALLORA_PROTOS_DIR)"

	# Run protoc via uv/venv; evaluate `find` at recipe time with $$()
	$(PYTHON_COMMAND) -m grpc_tools.protoc \
		--proto_path="$(ALLORA_CHAIN_DIR)/x/emissions/proto" \
		--proto_path="$(ALLORA_CHAIN_DIR)/x/mint/proto" \
		--proto_path="$(COSMOS_SDK_DIR)/proto" \
		--proto_path="$(COSMOS_PROTO_DIR)/proto" \
		--proto_path="$(FEEMARKET_DIR)/proto" \
		--proto_path="$(GOOGLEAPIS_DIR)" \
		--proto_path="$(GOGOPROTO_DIR)" \
		--python_betterproto2_out="$(ALLORA_PROTOS_DIR)" \
		--python_betterproto2_opt=client_generation=async \
		$$(find "$(ALLORA_CHAIN_DIR)/x/emissions/proto" -type f -name '*.proto') \
		$$(find "$(ALLORA_CHAIN_DIR)/x/mint/proto" -type f -name '*.proto') \
		$$(find "$(COSMOS_SDK_DIR)/proto" -type f -name '*.proto') \
		$$(find "$(FEEMARKET_DIR)/proto/feemarket" -type f -name '*.proto')

	$(PYTHON_COMMAND) scripts/generate_custom_message_pool.py \
		--out "$(ALLORA_PROTOS_DIR)"

	# ensure packages are importable
	find "$(ALLORA_PROTOS_DIR)"/ -type d -exec sh -c 'touch "$$1/__init__.py"' _ {} \;

	touch "$@"

# Convenience alias
.PHONY: proto
proto: $(PROTO_STAMP)

# --- Interface generation
$(INTERFACE_STAMP): \
  $(PROTO_STAMP) \
  scripts/generate_interfaces_from_protos.py \
  scripts/templates/interface.py.jinja \
  scripts/templates/interface__init__.py.jinja \
  Makefile \
  | $(INTERFACE_OUT_DIR)
	rm -rf "$(INTERFACE_OUT_DIR)"
	mkdir -p "$(INTERFACE_OUT_DIR)"

	$(PYTHON_COMMAND) scripts/generate_interfaces_from_protos.py \
		--out "$(INTERFACE_OUT_DIR)" \
		--include-tags \
			emissions.v9 \
			emissions.v10 \
			mint.v5 \
			cosmos.tx \
			cosmos.base.tendermint.v1beta1 \
			cosmos.auth.v1beta1 \
			cosmos.bank.v1beta1 \
			feemarket.v1 \
		--proto-files-dirs \
			"$(ALLORA_CHAIN_DIR)/x" \
			"$(COSMOS_SDK_DIR)/proto" \
			"$(FEEMARKET_DIR)/proto/feemarket" \
		--include-dirs \
			"$(ALLORA_CHAIN_DIR)/x/emissions/proto" \
			"$(ALLORA_CHAIN_DIR)/x/mint/proto" \
			"$(COSMOS_SDK_DIR)/proto" \
			"$(COSMOS_PROTO_DIR)/proto" \
			"$(FEEMARKET_DIR)/proto" \
			"$(GOGOPROTO_DIR)" \
			"$(GOOGLEAPIS_DIR)" \
		--base-import-path "allora_sdk.rpc_client.protos"

	touch "$(INTERFACE_OUT_DIR)/__init__.py"
	touch "$@"

.PHONY: interfaces
interfaces: $(INTERFACE_STAMP)

# --- REST client generation
$(REST_STAMP): \
  $(PROTO_STAMP) \
  $(INTERFACE_STAMP) \
  scripts/generate_rest_client_from_protos.py \
  scripts/templates/rest_client.py.jinja \
  Makefile \
  | $(REST_CLIENT_OUT_DIR)
	rm -rf "$(REST_CLIENT_OUT_DIR)"
	mkdir -p "$(REST_CLIENT_OUT_DIR)"

	$(PYTHON_COMMAND) scripts/generate_rest_client_from_protos.py \
		--out "$(REST_CLIENT_OUT_DIR)" \
		--include-tags \
			emissions.v9 \
			emissions.v10 \
			mint.v5 \
			cosmos.tx \
			cosmos.base.tendermint.v1beta1 \
			cosmos.auth.v1beta1 \
			cosmos.bank.v1beta1 \
			feemarket.v1 \
		--proto-files-dirs \
			"$(ALLORA_CHAIN_DIR)/x" \
			"$(COSMOS_SDK_DIR)/proto" \
			"$(FEEMARKET_DIR)/proto/feemarket" \
		--include-dirs \
			"$(ALLORA_CHAIN_DIR)/x/emissions/proto" \
			"$(ALLORA_CHAIN_DIR)/x/mint/proto" \
			"$(COSMOS_SDK_DIR)/proto" \
			"$(COSMOS_PROTO_DIR)/proto" \
			"$(FEEMARKET_DIR)/proto" \
			"$(GOGOPROTO_DIR)" \
			"$(GOOGLEAPIS_DIR)" \
		--base-import-path "allora_sdk.rpc_client.protos" \
		--interface-import-path "allora_sdk.rpc_client.interfaces"

	touch "$(REST_CLIENT_OUT_DIR)/__init__.py"
	touch "$@"

.PHONY: rest
rest: $(REST_STAMP)

# --- gRPC wrapper generation
$(GRPC_STAMP): \
  $(PROTO_STAMP) \
  $(INTERFACE_STAMP) \
  scripts/generate_grpc_client_wrappers.py \
  scripts/templates/grpc_client.py.jinja \
  scripts/templates/grpc__init__.py.jinja \
  Makefile \
  | $(GRPC_WRAPPER_OUT_DIR)
	rm -rf "$(GRPC_WRAPPER_OUT_DIR)"
	mkdir -p "$(GRPC_WRAPPER_OUT_DIR)"

	$(PYTHON_COMMAND) scripts/generate_grpc_client_wrappers.py \
		--out "$(GRPC_WRAPPER_OUT_DIR)" \
		--include-tags \
			emissions.v9 \
			emissions.v10 \
			mint.v5 \
			cosmos.tx \
			cosmos.base.tendermint.v1beta1 \
			cosmos.auth.v1beta1 \
			cosmos.bank.v1beta1 \
			feemarket.v1 \
		--proto-files-dirs \
			"$(ALLORA_CHAIN_DIR)/x" \
			"$(COSMOS_SDK_DIR)/proto" \
			"$(FEEMARKET_DIR)/proto/feemarket" \
		--include-dirs \
			"$(ALLORA_CHAIN_DIR)/x/emissions/proto" \
			"$(ALLORA_CHAIN_DIR)/x/mint/proto" \
			"$(COSMOS_SDK_DIR)/proto" \
			"$(COSMOS_PROTO_DIR)/proto" \
			"$(FEEMARKET_DIR)/proto" \
			"$(GOGOPROTO_DIR)" \
			"$(GOOGLEAPIS_DIR)" \
		--base-import-path "allora_sdk.rpc_client.protos" \
		--interface-import-path "allora_sdk.rpc_client.interfaces"

	touch "$(GRPC_WRAPPER_OUT_DIR)/__init__.py"
	touch "$@"

.PHONY: grpc
grpc: $(GRPC_STAMP)

# --- Clean
.PHONY: clean
clean:
	rm -rf "$(ALLORA_PROTOS_DIR)" "$(INTERFACE_OUT_DIR)" "$(REST_CLIENT_OUT_DIR)" "$(GRPC_WRAPPER_OUT_DIR)" "$(PROTO_DEPS)"

.PHONY: distclean
distclean: clean
	rm -rf "$(PROTO_DEPS)"

.PHONY: test
test:
	tox run-parallel
