SHELL := /bin/bash
VENV_PY   := .venv/bin/python
VENV_PIP  := .venv/bin/pip
RUFF      := .venv/bin/ruff
PYTEST    := .venv/bin/pytest
BUILD     := .venv/bin/python -m build
EDGEMINT  := .venv/bin/edgemint

# Detect the current version from pyproject.toml (requires Python ≥ 3.11)
VERSION   := $(shell $(VENV_PY) -c \
  "import tomllib,pathlib; print(tomllib.loads(pathlib.Path('pyproject.toml').read_text())['project']['version'])" \
  2>/dev/null || echo "unknown")

.PHONY: help bootstrap doctor fmt fmt-check lint \
        test test-unit test-e2e \
        golden fixtures-download examples \
        build clean \
        release-check release-tag release-dry-run

# ─── Help ────────────────────────────────────────────────────────────────────

help: ## Show this command catalog
	@printf '\n'
	@printf '  \033[1medgemint\033[0m — DOCX style extraction and regeneration CLI\n'
	@printf '  version: \033[36m%s\033[0m\n' "$(VERSION)"
	@printf '\n'
	@printf '\033[1m  Development\033[0m\n'
	@printf '  %-22s %s\n' "bootstrap"       "Create/update the local virtualenv"
	@printf '  %-22s %s\n' "doctor"          "Check the local toolchain"
	@printf '  %-22s %s\n' "fmt"             "Auto-format source tree"
	@printf '  %-22s %s\n' "fmt-check"       "Verify formatting without changing files"
	@printf '  %-22s %s\n' "lint"            "Run static checks (ruff)"
	@printf '  %-22s %s\n' "test"            "Run the full test suite with coverage"
	@printf '  %-22s %s\n' "test-unit"       "Run unit tests only"
	@printf '  %-22s %s\n' "test-e2e"        "Run CLI and golden end-to-end tests"
	@printf '\n'
	@printf '\033[1m  Data & Examples\033[0m\n'
	@printf '  %-22s %s\n' "fixtures-download" "Download committed golden DOCX fixtures"
	@printf '  %-22s %s\n' "golden"          "Rebuild golden extraction/round-trip snapshots"
	@printf '  %-22s %s\n' "examples"        "Rebuild all Packt example DOCX proofs"
	@printf '\n'
	@printf '\033[1m  Build & Release\033[0m\n'
	@printf '  %-22s %s\n' "build"           "Build wheel + sdist into dist/"
	@printf '  %-22s %s\n' "release-check"   "Pre-flight checklist before tagging a release"
	@printf '  %-22s %s\n' "release-dry-run" "Build & inspect dist/ without publishing"
	@printf '  %-22s %s\n' "release-tag"     "Tag HEAD as vVERSION and push (triggers CI release)"
	@printf '  %-22s %s\n' "clean"           "Remove build/test artifacts"
	@printf '\n'
	@printf '\033[1m  Recommended flows\033[0m\n'
	@printf '  bootstrap → fmt → lint → test → build\n'
	@printf '  fixtures-download → golden → test-e2e\n'
	@printf '  release-check → release-tag\n'
	@printf '\n'

# ─── Bootstrap & Doctor ──────────────────────────────────────────────────────

bootstrap: ## Create/update the local virtualenv and install dev tooling
	@test -d .venv || python3 -m venv .venv
	$(VENV_PIP) install --upgrade pip
	$(VENV_PIP) install -e '.[dev,pandoc]'

doctor: ## Check the local toolchain used by edgemint
	@printf '\n\033[1mInterpreter\033[0m\n'
	@$(VENV_PY) -V
	@printf '\n\033[1mPackage\033[0m\n'
	@$(EDGEMINT) version
	@printf '\n\033[1mPandoc\033[0m\n'
	@$(VENV_PY) -c 'from edgemint.pandoc import get_pandoc_version; print(get_pandoc_version() or "missing")'
	@printf '\n\033[1mRuff\033[0m\n'
	@$(RUFF) --version
	@printf '\n'

# ─── Format & Lint ───────────────────────────────────────────────────────────

fmt: ## Auto-format the source tree
	$(RUFF) format src tests scripts

fmt-check: ## Verify formatting without changing files
	$(RUFF) format --check src tests scripts

fmt-enforce: ## Auto-fix all formatting issues (required before commit)
	$(RUFF) check src tests scripts --fix
	$(RUFF) format src tests scripts
	@printf '\033[32m✓\033[0m Auto-fixes applied. Review changes and commit.\n'

lint: ## Run static checks
	$(RUFF) check src tests scripts
	$(RUFF) format --check src tests scripts

pre-commit: fmt-enforce lint test ## Run fmt-enforce → lint → test before pushing
	@printf '\033[32m✓\033[0m All pre-commit checks passed.\n'

# ─── Test ────────────────────────────────────────────────────────────────────

test: ## Run the full test suite with coverage
	$(PYTEST) --cov=src/edgemint --cov-fail-under=100

test-unit: ## Run unit-focused tests only
	$(PYTEST) --cov=src/edgemint --cov-fail-under=100 \
	  tests/test_validators.py tests/test_resolver.py \
	  tests/test_diffing.py tests/test_markdown.py

test-e2e: ## Run CLI and golden end-to-end tests
	$(PYTEST) --cov=src/edgemint --cov-fail-under=100 \
	  tests/test_cli_e2e.py tests/test_golden_e2e.py

# ─── Data & Examples ─────────────────────────────────────────────────────────

fixtures-download: ## Download the committed golden DOCX fixtures
	./scripts/download_golden_fixtures.sh

golden: ## Rebuild golden extraction and round-trip snapshots
	$(VENV_PY) scripts/build_golden_dataset.py

examples: ## Rebuild all Packt example DOCX proofs
	$(EDGEMINT) extract-styles examples/packt-style.docx -o examples/packt-style.styles.json
	$(EDGEMINT) extract examples/packt-style.docx -o examples/packt-style.bundle
	$(VENV_PY) scripts/build_packt_author_guide.py
	$(EDGEMINT) apply-styles examples/packt-style-example.md       examples/packt-style.styles.json -o examples/packt-style-example.docx       --media examples
	$(EDGEMINT) apply-styles examples/packt-book-chapter.md        examples/packt-style.styles.json -o examples/packt-book-chapter.docx        --media examples
	$(EDGEMINT) apply-styles examples/01-transformer.md            examples/packt-style.styles.json -o examples/01-transformer.docx            --media examples
	$(EDGEMINT) apply-styles examples/packt-style-author-guide.md  examples/packt-style.styles.json -o examples/packt-style-author-guide.docx  --media examples

# ─── Build ───────────────────────────────────────────────────────────────────

build: ## Build wheel and sdist into dist/
	$(BUILD)

# ─── Release ─────────────────────────────────────────────────────────────────

release-check: ## Pre-flight checklist — run before tagging a release
	@printf '\n\033[1m  Release pre-flight for v%s\033[0m\n\n' "$(VERSION)"
	@# 1. working tree must be clean
	@if [ -n "$$(git status --porcelain)" ]; then \
	  printf '  \033[31m✗\033[0m Working tree is dirty — commit or stash changes first\n\n'; \
	  git status --short; exit 1; \
	else \
	  printf '  \033[32m✓\033[0m Working tree is clean\n'; fi
	@# 2. on main/master branch
	@BRANCH=$$(git rev-parse --abbrev-ref HEAD); \
	if [ "$$BRANCH" != "main" ] && [ "$$BRANCH" != "master" ]; then \
	  printf '  \033[33m!\033[0m On branch $$BRANCH (expected main or master)\n'; \
	else \
	  printf '  \033[32m✓\033[0m On branch $$BRANCH\n'; fi
	@# 3. tag must not already exist
	@if git rev-parse "v$(VERSION)" >/dev/null 2>&1; then \
	  printf '  \033[31m✗\033[0m Tag v%s already exists\n\n' "$(VERSION)"; exit 1; \
	else \
	  printf '  \033[32m✓\033[0m Tag v%s does not exist yet\n' "$(VERSION)"; fi
	@# 4. lint
	@printf '  Running lint...\n'
	@$(RUFF) check src tests scripts && $(RUFF) format --check src tests scripts \
	  && printf '  \033[32m✓\033[0m Lint passed\n' \
	  || { printf '  \033[31m✗\033[0m Lint failed\n'; exit 1; }
	@# 5. tests
	@printf '  Running tests...\n'
	@$(PYTEST) -q --cov=src/edgemint --cov-fail-under=100 \
	  && printf '  \033[32m✓\033[0m All tests passed\n' \
	  || { printf '  \033[31m✗\033[0m Tests failed\n'; exit 1; }
	@printf '\n  \033[32mAll checks passed.\033[0m Run \033[1mmake release-tag\033[0m to publish.\n\n'

release-dry-run: build ## Build dist/ and verify packages without publishing
	@printf '\n\033[1m  Dry-run dist/ contents for v%s\033[0m\n\n' "$(VERSION)"
	@ls -lh dist/
	@printf '\n'
	@$(VENV_PY) -m twine check dist/* 2>/dev/null \
	  || $(VENV_PY) -c "import zipfile,sys; \
	    [print(f'  wheel: {n}') for z in sys.argv[1:] if z.endswith('.whl') \
	    for n in zipfile.ZipFile(z).namelist()[:6]]" dist/*.whl && printf '  (install twine for full check: pip install twine)\n'
	@printf '\n  \033[32mDist looks good.\033[0m Push the tag with \033[1mmake release-tag\033[0m.\n\n'

release-tag: ## Tag HEAD as vVERSION and push — triggers the CI Release workflow
	@if [ -n "$$(git status --porcelain)" ]; then \
	  printf '\033[31mError:\033[0m working tree is dirty. Commit first.\n'; exit 1; fi
	@printf 'Tagging \033[1mv%s\033[0m and pushing...\n' "$(VERSION)"
	git tag -a "v$(VERSION)" -m "Release v$(VERSION)"
	git push origin "v$(VERSION)"
	@printf '\n\033[32m✓\033[0m Tag pushed. The Release workflow is now running:\n'
	@printf '  https://github.com/raphaelmansuy/edgemint/actions\n\n'

# ─── Clean ───────────────────────────────────────────────────────────────────

clean: ## Remove local build and test artifacts
	@printf 'Removing build and test artifacts...\n'
	rm -rf build dist .pytest_cache .ruff_cache .coverage coverage.xml htmlcov
	@printf '\033[32m✓\033[0m Clean.\n'
