UV ?= uv
RUN := $(UV) run --locked
MLFLOW_URL ?= http://127.0.0.1:5000
MODEL_NAME ?= predictive-maintenance
MODEL_ALIAS ?= champion
PORT ?= 8000
API_HOST ?= 127.0.0.1
BATCH_SIZE ?= 350
LABEL_DELAY_HOURS ?= 24
ARCHIVE ?= MLOps_TP4_Nom_Prenom.zip
OBSERVABILITY_COMPOSE ?= observability/docker-compose.yml
OBSERVABILITY_ENV_FILE ?= observability/.env
COMPOSE_ENV_ARGS := $(if $(wildcard $(OBSERVABILITY_ENV_FILE)),--env-file $(OBSERVABILITY_ENV_FILE),)
IMAGE ?= maintenance-ml:tp4

.PHONY: install doctor lock export-requirements security-audit image-scan mlflow-server import-tp3 bootstrap-reference test lint api monitor operational-metrics performance-week2 decide export-handoff observability-up observability-up-host observability-down observability-down-host observability-check validate-submission report package

install:
	$(UV) sync --locked

doctor:
	@command -v $(UV) >/dev/null || { echo "uv est requis : https://docs.astral.sh/uv/getting-started/installation/"; exit 1; }
	@command -v git >/dev/null || { echo "git est requis"; exit 1; }
	@command -v curl >/dev/null || { echo "curl est requis"; exit 1; }
	@$(RUN) pytest --version
	@$(RUN) mlflow --version
	@$(RUN) ruff --version
	@echo "Environnement TP4 prêt"

lock:
	$(UV) lock

export-requirements:
	$(UV) export --locked --no-dev --no-hashes --no-header --no-emit-project --output-file requirements.txt

security-audit:
	$(UV) tool run --from pip-audit pip-audit --requirement requirements.txt

image-scan:
	command -v trivy >/dev/null || { echo "Trivy est requis pour ce contrôle optionnel"; exit 2; }
	trivy image --exit-code 1 --severity HIGH,CRITICAL "$(IMAGE)"

mlflow-server:
	$(RUN) mlflow server --backend-store-uri sqlite:///mlflow.db --host 127.0.0.1 --port 5000

import-tp3:
	test -n "$(TP3_DIR)" || { echo "Usage: make import-tp3 TP3_DIR=/chemin/vers/TP3"; exit 2; }
	PYTHONPATH=. $(RUN) python scripts/import_tp3.py --source "$(TP3_DIR)"

bootstrap-reference:
	PYTHONPATH=. $(RUN) python scripts/bootstrap_reference.py

test:
	mkdir -p reports
	PYTHONPATH=. $(RUN) python -m pytest -q --junitxml=reports/test_report.xml

lint:
	$(RUN) ruff check .

api:
	MLFLOW_TRACKING_URI=$(MLFLOW_URL) MODEL_NAME=$(MODEL_NAME) MODEL_ALIAS=$(MODEL_ALIAS) $(RUN) uvicorn maintenance_ml.api.main:app --host $(API_HOST) --port $(PORT)

monitor:
	$(RUN) python -m maintenance_ml.monitoring.drift

operational-metrics:
	$(RUN) python -m maintenance_ml.monitoring.operational --batch-size $(BATCH_SIZE) --label-delay-hours $(LABEL_DELAY_HOURS)

performance-week2:
	$(RUN) python -m maintenance_ml.monitoring.evaluate_labeled_batch

decide:
	$(RUN) python -m maintenance_ml.monitoring.decide_action

export-handoff:
	$(RUN) python scripts/export_handoff.py

observability-up:
	@command -v docker >/dev/null || { echo "Docker est requis pour Prometheus/Grafana"; exit 1; }
	@test -n "$${GRAFANA_ADMIN_PASSWORD:-}" -o -f "$(OBSERVABILITY_ENV_FILE)" || { echo "Définissez GRAFANA_ADMIN_PASSWORD ou copiez observability/.env.example vers observability/.env"; exit 2; }
	docker compose $(COMPOSE_ENV_ARGS) -f $(OBSERVABILITY_COMPOSE) up -d

observability-up-host:
	$(MAKE) observability-up OBSERVABILITY_COMPOSE="observability/docker-compose.yml -f observability/docker-compose.host.yml"

observability-down:
	docker compose $(COMPOSE_ENV_ARGS) -f $(OBSERVABILITY_COMPOSE) down

observability-down-host:
	$(MAKE) observability-down OBSERVABILITY_COMPOSE="observability/docker-compose.yml -f observability/docker-compose.host.yml"

observability-check:
	@for url in http://127.0.0.1:9090/-/ready http://127.0.0.1:3000/api/health; do \
		ready=0; \
		for attempt in $$(seq 1 30); do \
			if curl --fail --silent "$$url" >/dev/null; then ready=1; break; fi; \
			sleep 1; \
		done; \
		test "$$ready" -eq 1 || { echo "Service indisponible: $$url"; exit 1; }; \
	done
	@for attempt in $$(seq 1 30); do \
		if curl --fail --silent --get --data-urlencode 'query=up{job="tp3-serving-api"}' http://127.0.0.1:9090/api/v1/query | \
			python -c 'import json,sys; d=json.load(sys.stdin); assert any(r.get("value", [None, "0"])[1] == "1" for r in d.get("data", {}).get("result", []))'; then break; fi; \
		test "$$attempt" -lt 30 || { echo "Cible TP3 non UP dans Prometheus"; exit 1; }; sleep 1; \
	done
	@echo "Observabilité TP4 prête — Prometheus :9090, Grafana :3000"

validate-submission:
	PYTHONPATH=. $(RUN) python tests/validate_submission.py

report:
	mkdir -p reports/figures
	test -f reports/tp4_report.md || cp reports/tp4_report_template.md reports/tp4_report.md
	test -f reports/runbook.md || cp reports/runbook_template.md reports/runbook.md
	test -f reports/incident-timeline.md || cp reports/incident-timeline_template.md reports/incident-timeline.md
	test -f reports/postmortem.md || cp reports/postmortem_template.md reports/postmortem.md

package:
	$(MAKE) validate-submission
	PYTHONPATH=. $(RUN) python scripts/package_submission.py --output "$(ARCHIVE)"
