#!/usr/bin/env bash
set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "${SCRIPT_DIR}/../../.." && pwd)"
API_DIR="${REPO_ROOT}/api"
PROTO_DIR="./proto"
PROTOC_BIN="${PROTOC:-protoc}"
GO_MODULE="github.com/tech/sendico/pkg"
GO_OUT_DIR="./pkg"

# Ensure required tools exist
if ! command -v "${PROTOC_BIN}" >/dev/null 2>&1; then
  echo "[proto] protoc binary not found" >&2; exit 1
fi
if ! command -v protoc-gen-go >/dev/null 2>&1; then
  echo "[proto] protoc-gen-go is not installed" >&2; exit 1
fi
if ! command -v protoc-gen-go-grpc >/dev/null 2>&1; then
  echo "[proto] protoc-gen-go-grpc is not installed" >&2; exit 1
fi

info() { printf '[proto] %s\n' "$1"; }

# Try to determine the include path for well-known types (WKT) without hard failing
PROTOC_INCLUDE=""
# Prefer known locations on Alpine/Debian-like images
for cand in /usr/include /usr/local/include; do
  if [ -f "$cand/google/protobuf/descriptor.proto" ]; then
    PROTOC_INCLUDE="$cand"
    break
  fi
done

PROTOC_ARGS=""
if [ -n "${PROTOC_INCLUDE}" ]; then
  PROTOC_ARGS="-I=${PROTOC_INCLUDE}"
fi
PROTOC_ARGS="${PROTOC_ARGS} -I=.. -I=${PROTO_DIR}"

PROTOC_ARGS_MESSAGING=""
if [ -n "${PROTOC_INCLUDE}" ]; then
  PROTOC_ARGS_MESSAGING="-I=${PROTOC_INCLUDE}"
fi
PROTOC_ARGS_MESSAGING="${PROTOC_ARGS_MESSAGING} -I=${PROTO_DIR}"

generate_go() {
  # shellcheck disable=SC2086
  "${PROTOC_BIN}" \
    ${PROTOC_ARGS} \
    --go_out="${GO_OUT_DIR}" \
    --go_opt=module="${GO_MODULE}" \
    "$@"
}

generate_go_messaging() {
  # shellcheck disable=SC2086
  "${PROTOC_BIN}" \
    ${PROTOC_ARGS_MESSAGING} \
    --go_out="${GO_OUT_DIR}" \
    --go_opt=module="${GO_MODULE}" \
    "$@"
}

generate_go_with_grpc() {
  # shellcheck disable=SC2086
  "${PROTOC_BIN}" \
    ${PROTOC_ARGS} \
    --go_out="${GO_OUT_DIR}" \
    --go_opt=module="${GO_MODULE}" \
    --go-grpc_out="${GO_OUT_DIR}" \
    --go-grpc_opt=module="${GO_MODULE}" \
    "$@"
}

clean_pb_files() {
  local target="$1"
  if [ -d "${target}" ]; then
    find "${target}" -type f -name '*.pb.go' -delete
  fi
}

list_protos() {
  local search_dir="$1" maxdepth="${2:-}"
  if [ -n "$maxdepth" ]; then
    find "${search_dir}" -maxdepth "${maxdepth}" -type f -name '*.proto' | sort
  else
    find "${search_dir}" -type f -name '*.proto' | sort
  fi
}

cd "${API_DIR}"

messaging_files="$(find "${PROTO_DIR}" -maxdepth 1 -type f -name '*.proto' -exec basename {} \; | sort)"
if [ -n "${messaging_files}" ]; then
  info "Compiling messaging protos"
  rm -rf ./pkg/generated/gmessaging ./pkg/messaging/internal/generated
  set -- $messaging_files
  generate_go_messaging "$@"
fi

common_files="$(list_protos "${PROTO_DIR}/common" | sed 's#^\./##' | sed 's#^proto/#api/proto/#')"
if [ -n "${common_files}" ]; then
  info "Compiling common shared protos"
  clean_pb_files "./pkg/proto"
  set -- $common_files
  generate_go "$@"
fi

if [ -f "${PROTO_DIR}/ledger/v1/ledger.proto" ]; then
  info "Compiling ledger protos"
  clean_pb_files "./pkg/proto/ledger"
  generate_go_with_grpc "${PROTO_DIR}/ledger/v1/ledger.proto"
fi

if [ -f "${PROTO_DIR}/oracle/v1/oracle.proto" ]; then
  info "Compiling oracle protos"
  clean_pb_files "./pkg/proto/oracle"
  generate_go_with_grpc "${PROTO_DIR}/oracle/v1/oracle.proto"
fi

if [ -f "${PROTO_DIR}/gateway/chain/v1/chain.proto" ]; then
  info "Compiling chain gateway protos"
  clean_pb_files "./pkg/proto/gateway/chain"
  generate_go_with_grpc "${PROTO_DIR}/gateway/chain/v1/chain.proto"
fi

if [ -f "${PROTO_DIR}/gateway/mntx/v1/mntx.proto" ]; then
  info "Compiling Monetix gateway protos"
  clean_pb_files "./pkg/proto/gateway/mntx"
  generate_go_with_grpc "${PROTO_DIR}/gateway/mntx/v1/mntx.proto"
fi

if [ -f "${PROTO_DIR}/connector/v1/connector.proto" ]; then
  info "Compiling connector protos"
  clean_pb_files "./pkg/proto/connector"
  generate_go_with_grpc "${PROTO_DIR}/connector/v1/connector.proto"
fi

if [ -f "${PROTO_DIR}/payments/shared/v1/shared.proto" ]; then
  info "Compiling payments shared protos"
  clean_pb_files "./pkg/proto/payments/shared"
  generate_go_with_grpc "${PROTO_DIR}/payments/shared/v1/shared.proto"
fi

if [ -f "${PROTO_DIR}/payments/orchestration/v2/orchestration.proto" ]; then
  info "Compiling payments orchestration protos"
  clean_pb_files "./pkg/proto/payments/orchestration"
  generate_go_with_grpc "${PROTO_DIR}/payments/orchestration/v2/orchestration.proto"
fi

if [ -f "${PROTO_DIR}/payments/transfer/v1/transfer.proto" ]; then
  info "Compiling payments transfer protos"
  clean_pb_files "./pkg/proto/payments/transfer"
  generate_go "${PROTO_DIR}/payments/transfer/v1/transfer.proto"
fi

if [ -f "${PROTO_DIR}/payments/quotation/v2/interface.proto" ] || \
   [ -f "${PROTO_DIR}/payments/quotation/v2/quotation.proto" ]; then
  info "Compiling payments quotation protos"
  clean_pb_files "./pkg/proto/payments/quotation"
  if [ -f "${PROTO_DIR}/payments/quotation/v2/interface.proto" ]; then
    generate_go "api/proto/payments/quotation/v2/interface.proto"
  fi
  if [ -f "${PROTO_DIR}/payments/quotation/v2/quotation.proto" ]; then
    generate_go_with_grpc "api/proto/payments/quotation/v2/quotation.proto"
  fi
fi

if [ -f "${PROTO_DIR}/payments/endpoint/v1/endpoint.proto" ]; then
  info "Compiling payments endpoint protos"
  clean_pb_files "./pkg/proto/payments/endpoint"
  generate_go "${PROTO_DIR}/payments/endpoint/v1/endpoint.proto"
fi

if [ -f "${PROTO_DIR}/payments/methods/v1/methods.proto" ]; then
  info "Compiling payments methods protos"
  clean_pb_files "./pkg/proto/payments/methods"
  generate_go_with_grpc "${PROTO_DIR}/payments/methods/v1/methods.proto"
fi

if [ -f "${PROTO_DIR}/billing/fees/v1/fees.proto" ]; then
  info "Compiling billing fees protos"
  clean_pb_files "./pkg/proto/billing/fees"
  generate_go_with_grpc "${PROTO_DIR}/billing/fees/v1/fees.proto"
fi

if [ -f "${PROTO_DIR}/billing/documents/v1/documents.proto" ]; then
  info "Compiling billing documents protos"
  clean_pb_files "./pkg/proto/billing/documents"
  generate_go_with_grpc "${PROTO_DIR}/billing/documents/v1/documents.proto"
fi

info "Protobuf generation completed"
