SHELL := /bin/bash

# =============================================================================
# Configuration and Environment Variables
# =============================================================================

.DEFAULT_GOAL:=help
.ONESHELL:
.EXPORT_ALL_VARIABLES:
MAKEFLAGS += --no-print-directory
.SHELLFLAGS := -eu -o pipefail -c

# Rodete (Internal Linux) detection and overrides
ifneq ($(shell grep -s -q "rodete" /etc/os-release && echo "yes"),)
export PIP_INDEX_URL=https://pypi.org/simple
export UV_INDEX_URL=https://pypi.org/simple
export UV_DEFAULT_INDEX=https://pypi.org/simple
endif

# -----------------------------------------------------------------------------
# Display Formatting and Colors
# -----------------------------------------------------------------------------
BLUE := $(shell printf "\033[1;34m")
GREEN := $(shell printf "\033[1;32m")
RED := $(shell printf "\033[1;31m")
YELLOW := $(shell printf "\033[1;33m")
NC := $(shell printf "\033[0m")
INFO := $(shell printf "$(BLUE)ℹ$(NC)")
OK := $(shell printf "$(GREEN)✓$(NC)")
WARN := $(shell printf "$(YELLOW)⚠$(NC)")
ERROR := $(shell printf "$(RED)✖$(NC)")

# =============================================================================
# Help and Documentation
# =============================================================================

.PHONY: help
help:                                               ## Display this help text for Makefile
	@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n  make \033[36m<target>\033[0m\n"} /^[a-zA-Z0-9_-]+:.*?##/ { printf "  \033[36m%-18s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)

# =============================================================================
# Installation and Environment Setup
# =============================================================================

.PHONY: setup-env
setup-env:                                          ## Configure environment (detects Rodete vs standard Linux/macOS)
	@bash tools/scripts/setup-env.sh

.PHONY: install-uv
install-uv:                                         ## Install latest version of uv
	@echo "${INFO} Installing uv..."
	@curl -LsSf https://astral.sh/uv/install.sh | sh >/dev/null 2>&1
	@echo "${OK} UV installed successfully"

.PHONY: install
install: destroy clean setup-env                    ## Install the project, dependencies, and hooks
	@echo "${INFO} Starting fresh installation..."
	@uv python pin 3.12 >/dev/null 2>&1
	@uv venv >/dev/null 2>&1
	@uv sync --all-extras --dev
	@echo "${OK} Installation complete! 🎉"

.PHONY: destroy
destroy:                                            ## Destroy the virtual environment
	@echo "${INFO} Destroying virtual environment... 🗑️"
	@rm -rf .venv
	@echo "${OK} Virtual environment destroyed 🗑️"

# =============================================================================
# Dependency Management
# =============================================================================

.PHONY: upgrade
upgrade: setup-env                                  ## Upgrade all dependencies to latest stable versions
	@echo "${INFO} Updating all dependencies... 🔄"
	@uv lock --upgrade
	@uv sync --all-extras --dev
	@echo "${OK} Dependencies updated 🔄"
	@uvx prek autoupdate --cooldown-days 7 2>/dev/null || uv run pre-commit autoupdate
	@echo "${OK} Updated pre-commit hooks 🔄"

.PHONY: lock
lock: setup-env                                     ## Rebuild lockfiles from scratch
	@echo "${INFO} Rebuilding lockfiles... 🔄"
	@uv lock --upgrade >/dev/null 2>&1
	@echo "${OK} Lockfiles updated"

# =============================================================================
# Build and Release
# =============================================================================

.PHONY: build
build:                                             ## Build the package
	@echo "${INFO} Building package... 📦"
	@uv build >/dev/null 2>&1
	@echo "${OK} Package build complete"

.PHONY: release
release:                                           ## Bump version and create release (finalize pre-release or bump=major|minor|patch)
	@echo "${INFO} Preparing for release... 📦"
	@current_version="$$(grep -E '^current_version = ' pyproject.toml | head -n1 | cut -d'"' -f2)"; \
	case "$$current_version" in \
		*-*) \
			if [ -z "$(bump)" ] || [ "$(bump)" = "pre" ]; then \
				release_version="$${current_version%%-*}"; \
				echo "${INFO} Finalizing pre-release $$current_version -> $$release_version..."; \
				uv run bump-my-version bump --new-version "$$release_version" pre; \
			else \
				uv run bump-my-version bump "$(bump)"; \
			fi \
			;; \
		*) \
			if [ -z "$(bump)" ]; then \
				echo "${ERROR} Please specify 'bump' parameter for stable releases, e.g., make release bump=minor"; \
				echo "${INFO} Examples:"; \
				echo "  make release bump=patch            # 0.19.0 -> 0.19.1"; \
				echo "  make release bump=minor            # 0.19.0 -> 0.20.0"; \
				echo "  make release bump=major            # 0.19.0 -> 1.0.0"; \
				exit 1; \
			fi; \
			uv run bump-my-version bump "$(bump)"; \
			;; \
	esac
	@uv lock --upgrade-package pytest-databases >/dev/null 2>&1
	@make docs
	@make clean
	@make build
	@echo "${OK} Release complete 🎉"

.PHONY: pre-release
pre-release:                                       ## Set pre-release version (use version=X.Y.Z-alpha.N|beta.N|rc.N)
	@if [ -z "$(version)" ]; then \
		echo "${ERROR} Please specify 'version' parameter, e.g., make pre-release version=0.20.0-alpha.1"; \
		echo "${INFO} Examples:"; \
		echo "  make pre-release version=0.20.0-alpha.1   # First alpha for 0.20.0"; \
		echo "  make pre-release version=0.20.0-alpha.2   # Next alpha"; \
		echo "  make pre-release version=0.20.0-beta.1    # First beta"; \
		echo "  make pre-release version=0.20.0-rc.1      # Release candidate"; \
		echo "  make release                              # Finalize to 0.20.0"; \
		exit 1; \
	fi
	@echo "${INFO} Setting pre-release version to $(version)... 📦"
	@make clean
	@uv run bump-my-version bump --new-version $(version) pre
	@uv lock --upgrade-package pytest-databases >/dev/null 2>&1
	@make build
	@echo "${OK} Pre-release $(version) ready 🎉"
	@echo "${INFO} Next steps:"
	@echo "  1. Commit and push changes: git push origin HEAD"
	@echo "  2. Create GitHub pre-release: gh release create v$(version) --prerelease --generate-notes --title 'v$(version)'"

# =============================================================================
# Cleaning and Maintenance
# =============================================================================

.PHONY: clean
clean:                                              ## Cleanup temporary build artifacts
	@echo "${INFO} Cleaning working directory... 🧹"
	@rm -rf .pytest_cache .ruff_cache .hypothesis build/ dist/ .eggs/ .coverage coverage.xml coverage.json htmlcov/ .pytest_cache tests/.pytest_cache tests/**/.pytest_cache .mypy_cache .unasyncd_cache/ .auto_pytabs_cache node_modules >/dev/null 2>&1
	@find . -name '*.egg-info' -exec rm -rf {} + >/dev/null 2>&1
	@find . -type f -name '*.egg' -exec rm -f {} + >/dev/null 2>&1
	@find . -name '*.pyc' -exec rm -f {} + >/dev/null 2>&1
	@find . -name '*.pyo' -exec rm -f {} + >/dev/null 2>&1
	@find . -name '*~' -exec rm -f {} + >/dev/null 2>&1
	@find . -name '__pycache__' -exec rm -rf {} + >/dev/null 2>&1
	@find . -name '.ipynb_checkpoints' -exec rm -rf {} + >/dev/null 2>&1
	@echo "${OK} Working directory cleaned"
	$(MAKE) docs-clean

# =============================================================================
# Testing and Quality Checks
# =============================================================================

.PHONY: test
test:                                              ## Run the tests
	@echo "${INFO} Running test cases... 🧪"
	@uv run pytest --quiet --runpytest subprocess
	@echo "${OK} Tests passed ✨"

.PHONY: coverage
coverage:                                          ## Run tests with coverage report
	@echo "${INFO} Running tests with coverage... 📊"
	@uv run pytest --cov -n auto --quiet
	@uv run coverage html >/dev/null 2>&1
	@uv run coverage xml >/dev/null 2>&1
	@echo "${OK} Coverage report generated ✨"

# -----------------------------------------------------------------------------
# Type Checking
# -----------------------------------------------------------------------------

.PHONY: mypy
mypy:                                              ## Run mypy
	@echo "${INFO} Running mypy... 🔍"
	@uv run dmypy run
	@echo "${OK} Mypy checks passed ✨"

.PHONY: mypy-nocache
mypy-nocache:                                      ## Run Mypy without cache
	@echo "${INFO} Running mypy without cache... 🔍"
	@uv run mypy
	@echo "${OK} Mypy checks passed ✨"

.PHONY: pyright
pyright:                                           ## Run pyright
	@echo "${INFO} Running pyright... 🔍"
	@uv run pyright
	@echo "${OK} Pyright checks passed ✨"

.PHONY: type-check
type-check: mypy-nocache pyright                   ## Run all type checking

# -----------------------------------------------------------------------------
# Linting, Formatting, and Security
# -----------------------------------------------------------------------------

.PHONY: prek
prek:                                              ## Run prek / pre-commit hooks
	@echo "${INFO} Running pre-commit checks... 🔎"
	@NODE_OPTIONS="--no-deprecation --disable-warning=ExperimentalWarning" uvx prek run --color=always --all-files 2>/dev/null || NODE_OPTIONS="--no-deprecation --disable-warning=ExperimentalWarning" uv run pre-commit run --color=always --all-files
	@echo "${OK} Pre-commit checks passed ✨"

.PHONY: pre-commit
pre-commit: prek                                   ## Alias for prek

.PHONY: slotscheck
slotscheck:                                        ## Run slotscheck
	@echo "${INFO} Running slots check... 🔍"
	@uv run slotscheck src/pytest_databases
	@echo "${OK} Slots check passed ✨"

.PHONY: zizmor
zizmor:                                            ## Audit GitHub Actions workflows with zizmor
	@echo "${INFO} Auditing GitHub Actions workflows (zizmor)... 🛡️"
	@uv run zizmor --strict-collection .github/workflows
	@echo "${OK} Workflow security audit passed ✨"

.PHONY: fix
fix:                                               ## Run code formatters
	@echo "${INFO} Running code formatters... 🔧"
	@uv run ruff check --fix --unsafe-fixes
	@uv run ruff format
	@echo "${OK} Code formatting complete ✨"

.PHONY: lint
lint: prek type-check slotscheck zizmor            ## Run all linting, typing, and security checks

.PHONY: check-all
check-all: lint test coverage                      ## Run all checks (lint, test, coverage)

# =============================================================================
# Documentation
# =============================================================================

.PHONY: docs-clean
docs-clean:                                        ## Clean documentation build
	@echo "${INFO} Cleaning documentation build assets... 🧹"
	@rm -rf docs/_build >/dev/null 2>&1
	@echo "${OK} Documentation assets cleaned"

.PHONY: docs-serve
docs-serve:                                        ## Serve documentation locally
	@echo "${INFO} Starting documentation server... 📚"
	@uv run sphinx-autobuild docs docs/_build/ -j auto --watch src/pytest_databases --watch docs --watch tests --watch CONTRIBUTING.rst --open-browser

.PHONY: docs
docs: docs-clean                                   ## Build documentation
	@echo "${INFO} Building documentation... 📝"
	@uv run sphinx-build -M html docs docs/_build/ -E -a -j auto -W --keep-going
	@echo "${OK} Documentation built successfully"

.PHONY: docs-linkcheck
docs-linkcheck:                                    ## Check documentation links
	@echo "${INFO} Checking documentation links... 🔗"
	@uv run sphinx-build -b linkcheck ./docs ./docs/_build -D linkcheck_ignore='http://.*','https://.*'
	@echo "${OK} Link check complete"

.PHONY: docs-linkcheck-full
docs-linkcheck-full:                               ## Run full documentation link check
	@echo "${INFO} Running full link check... 🔗"
	@uv run sphinx-build -b linkcheck ./docs ./docs/_build -D linkcheck_anchors=0
	@echo "${OK} Full link check complete"
