# Makefile for managing the Dockerized Python application

# --- Configuration ---
# Use the current directory name as the default image name
IMAGE_NAME := $(shell basename $(CURDIR))
# Default tag
TAG := latest
# Placeholder for a remote registry (e.g., your Docker Hub username or Gitea instance)
# For Gitea: REGISTRY ?= your-gitea-host:port/owner
# Example: REGISTRY ?= localhost:3000/myuser
REGISTRY ?= your-registry-username

# Default internal application port (exposed to Traefik)
PORT := 8000


# Function to find next free host port for the app and ask user
# This function will echo the chosen port if successful, or exit with an error.
define check_app_port_free
    @local start_port=$(PORT); \
    local found_port=$$start_port; \
    local is_free=false; \
    \
    if ! ss -tulnp | grep ":$$start_port " > /dev/null; then \
        echo "$$start_port"; \
        exit 0; \
    fi; \
    \
    echo "Port $$start_port is busy. Searching for a free port for the app..."; >&2; \
    while ! $$is_free; do \
        if ! ss -tulnp | grep ":$$found_port " > /dev/null; then \
            is_free=true; \
        else \
            ((found_port++)); \
            if [ "$$found_port" -gt 65535 ]; then \
                echo "ERROR: No free ports found up to 65535. Aborting." >&2; \
                exit 1; \
            fi; \
        fi; \
    done; \
    \
    echo "Port $$start_port is busy. I found port $$found_port to be free for the app." >&2; \
    read -p "Do you want to use port $$found_port for the app? (y/N): " choice; \
    case "$$choice" in \
        y|Y ) \
            echo "$$found_port"; \
            ;; \
        * ) \
            echo "Operation cancelled by user." >&2; \
            exit 1; \
            ;; \
    esac;
endef

# --- Docker Commands ---

.PHONY: build
build:
	@echo "Building Docker image: $(IMAGE_NAME):$(TAG)"
	docker build -t $(IMAGE_NAME):$(TAG) .

.PHONY: run
run:
	@export SELECTED_HOST_PORT=$(shell bash -c 'func() { $(check_app_port_free) }; func') && \
	echo "Using host port $$SELECTED_HOST_PORT for single app container" && \
	docker run -d -p $$SELECTED_HOST_PORT:$(PORT) --name $(IMAGE_NAME) $(IMAGE_NAME):$(TAG)

.PHONY: stop
stop:
	@echo "Stopping Docker container: $(IMAGE_NAME)"
	docker stop $(IMAGE_NAME) || true
	docker rm $(IMAGE_NAME) || true

.PHONY: logs
logs:
	@echo "Showing logs for container: $(IMAGE_NAME)"
	docker logs -f $(IMAGE_NAME)

.PHONY: shell
shell:
	@echo "Accessing shell in container: $(IMAGE_NAME)"
	docker exec -it $(IMAGE_NAME) /bin/bash

# --- Docker Compose Commands ---

.PHONY: up
up:
	@echo "Starting development environment with Docker Compose (integrating with external Traefik)..."
	docker-compose up --build -d

.PHONY: down
down:
	@echo "Stopping development environment with Docker Compose..."
	docker-compose down

# --- Image Management ---

.PHONY: tag
tag:
	@echo "Tagging image $(IMAGE_NAME):$(TAG) as $(REGISTRY)/$(IMAGE_NAME):$(TAG)"
	docker tag $(IMAGE_NAME):$(TAG) $(REGISTRY)/$(IMAGE_NAME):$(TAG)

.PHONY: push
push: tag
	@echo "Pushing image $(REGISTRY)/$(IMAGE_NAME):$(TAG) to registry..."
	docker push $(REGISTRY)/$(IMAGE_NAME):$(TAG)

# --- Cleanup ---

.PHONY: clean
clean:
	@echo "Cleaning up stopped containers and dangling images..."
	docker container prune -f
	docker image prune -f

.PHONY: help
help:
	@echo "Available commands:"
	@echo "  build   - Build the Docker image"
	@echo "  run     - Run the Docker container"
	@echo "  stop    - Stop and remove the Docker container"
	@echo "  logs    - Follow the logs of the container"
	@echo "  shell   - Get a shell inside the running container"
	@echo "  up      - Start the dev environment with docker-compose (integrates with external Traefik)"
	@echo "  down    - Stop the dev environment with docker-compose"
	@echo "  tag     - Tag the image for a registry"
	@echo "  push    - Push the image to a registry (after tagging)"
	@echo "  clean   - Clean up unused containers and images"
	@echo "  help    - Show this help message"

.DEFAULT_GOAL := help
