.PHONY: help install install-deps detect-usb configure diagnose
.PHONY: firmware firmware-stop cli-shell
.PHONY: backend backend-stop
.PHONY: frontend frontend-build frontend-stop
.PHONY: stack-start stack-stop
.PHONY: docker-up docker-down docker-build docker-logs
.PHONY: web web-bg web-logs web-test web-stop web-legacy
.PHONY: test test-e2e test-e2e-new test-integration test-all test-auto
.PHONY: clean format lint dev-install stop

VENV = .venv
PYTHON = $(VENV)/bin/python
PIP = $(VENV)/bin/pip

# Load ports from .env if available
-include .env
export

# Default ports (fallback if .env not loaded)
NPM ?= $(shell which npm 2>/dev/null || echo '/usr/share/nodejs/corepack/shims/npm')

# Healthcheck helpers
define wait_for_port
	@echo "⏳  Waiting for $(1) on port $(2)..."
	@for i in $$(seq 1 $(3)); do \
		if curl -sf http://localhost:$(2)/health >/dev/null 2>&1 || \
		   curl -sf http://localhost:$(2) >/dev/null 2>&1 || \
		   nc -z localhost $(2) 2>/dev/null; then \
			echo "✅  $(1) is ready!"; break; \
		fi; \
		if [ $$i -eq $(3) ]; then echo "❌  $(1) failed to start"; exit 1; fi; \
		sleep 1; \
	done
endef

define wait_for_mqtt
	@echo "⏳  Waiting for MQTT broker..."
	@for i in $$(seq 1 $(1)); do \
		if nc -z $(MQTT_BROKER_HOST) $(MQTT_BROKER_PORT) 2>/dev/null || \
		   timeout 1 bash -c '</dev/tcp/$(MQTT_BROKER_HOST)/$(MQTT_BROKER_PORT)' 2>/dev/null; then \
			echo "✅  MQTT broker is ready!"; break; \
		fi; \
		if [ $$i -eq $(1) ]; then echo "❌  MQTT broker failed to start"; exit 1; fi; \
		sleep 1; \
	done
endef
BACKEND_HOST ?= 0.0.0.0
BACKEND_PORT ?= 8001
FRONTEND_HOST ?= localhost
FRONTEND_PORT ?= 3000
MQTT_BROKER_HOST ?= localhost
MQTT_BROKER_PORT ?= 1883

# Helper to check and free port
define check_port
	@PORT=$(1); \
	PID=$$(lsof -ti :$$PORT 2>/dev/null || netstat -tlnp 2>/dev/null | grep ":$$PORT " | awk '{print $$7}' | cut -d'/' -f1 | head -1); \
	if [ -n "$$PID" ]; then \
		echo "Port $$PORT is in use by PID $$PID. Stopping..."; \
		kill -9 $$PID 2>/dev/null || true; \
		sleep 1; \
	fi
endef

# ── Help ────────────────────────────────────────────────────
help: ## Show this help message
	@echo "Available targets:"
	@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "  \033[36m%-20s\033[0m %s\n", $$1, $$2}'

# ── Installation ────────────────────────────────────────────
install: ## Full installation (system deps, udev rules, venv, python deps)
	@echo "Running full installation..."
	@bash -c 'if [ \$$EUID -ne 0 ]; then echo "Running without sudo. For udev rules, run: sudo make install"; fi'
	bash setup.sh

install-deps: ## Install all deps (firmware + backend + frontend)
	bash scripts/install-deps.sh

$(VENV)/bin/activate: requirements.txt pyproject.toml
	python3 -m venv $(VENV)
	$(PIP) install --upgrade pip
	$(PIP) install -e .
	$(PIP) install -r firmware/requirements.txt
	$(PIP) install -r backend/requirements.txt

# ── USB / Diagnostics ──────────────────────────────────────
detect-usb: $(VENV)/bin/activate ## Detect USB device
	@echo "Detecting Pololu USB device..."
	$(PYTHON) detect_usb.py

configure: $(VENV)/bin/activate detect-usb ## Auto-configure config.json
	@echo "Auto-configuring settings..."
	$(PYTHON) detect_usb.py | grep -A20 "Suggested config" | tail -n +2 > /tmp/usb_config.json 2>/dev/null || true
	@echo "Run 'make detect-usb' to see device config, then update config.json"

diagnose: $(VENV)/bin/activate ## Run USB diagnostic tool
	@echo "Running USB diagnostics..."
	$(PYTHON) diagnose_usb.py

# ── Firmware (motor control + MQTT) ────────────────────────
firmware: $(VENV)/bin/activate ## Start firmware service (motor + MQTT)
	@echo "Starting firmware (MQTT motor controller)..."
	MQTT_BROKER_HOST=$(MQTT_BROKER_HOST) MQTT_BROKER_PORT=$(MQTT_BROKER_PORT) \
		$(PYTHON) -m firmware.main

firmware-stop: ## Stop firmware service
	@pkill -f 'firmware.main' 2>/dev/null && echo "Firmware stopped" || echo "Firmware not running"

cli-shell: $(VENV)/bin/activate ## Interactive CLI shell for motor control
	@echo "Starting CLI shell..."
	$(PYTHON) -m firmware.cli_shell

# ── Backend (FastAPI REST + WS) ────────────────────────────
backend: $(VENV)/bin/activate ## Start backend API server
	$(call check_port,$(BACKEND_PORT))
	@echo "Starting backend on http://$(BACKEND_HOST):$(BACKEND_PORT) ..."
	MQTT_BROKER_HOST=$(MQTT_BROKER_HOST) MQTT_BROKER_PORT=$(MQTT_BROKER_PORT) \
	BACKEND_HOST=$(BACKEND_HOST) BACKEND_PORT=$(BACKEND_PORT) \
		$(PYTHON) -m backend.app

backend-stop: ## Stop backend server
	@pkill -f 'backend.app' 2>/dev/null && echo "Backend stopped" || echo "Backend not running"

# ── Frontend (React) ───────────────────────────────────────
frontend: ## Start frontend dev server
	$(call check_port,$(FRONTEND_PORT))
	@echo "Starting frontend on http://$(FRONTEND_HOST):$(FRONTEND_PORT) ..."
	cd frontend && npm run dev -- --port $(FRONTEND_PORT) --host $(FRONTEND_HOST)

frontend-build: ## Build frontend for production
	cd frontend && npm run build

frontend-stop: ## Stop frontend dev server
	@pkill -f 'vite' 2>/dev/null && echo "Frontend stopped" || echo "Frontend not running"

# ── Full stack (no Docker) ─────────────────────────────────

stack-stop: ## Stop all services
	@echo "Stopping all services..."
	@pkill -f 'firmware.main' 2>/dev/null || true
	@pkill -f 'backend.app' 2>/dev/null || true
	@pkill -f 'vite' 2>/dev/null || true
	@pkill -f 'python web_panel.py' 2>/dev/null || true
	@echo "All services stopped"

# ── Docker ──────────────────────────────────────────────────
docker-build: ## Build Docker images
	docker compose -f docker-compose.fullstack.yml build

docker-up: ## Start full stack with Docker
	docker compose -f docker-compose.fullstack.yml up -d
	@echo ""
	@echo "Services running:"
	@echo "  Frontend:  http://localhost:3000"
	@echo "  Backend:   http://localhost:8000"
	@echo "  MQTT:      localhost:1883"

docker-down: ## Stop Docker stack
	docker compose -f docker-compose.fullstack.yml down

docker-logs: ## Show Docker logs
	docker compose -f docker-compose.fullstack.yml logs -f

# ── Web (new fullstack - backend + frontend + MQTT) ───────────────
web: ## Start all services without Docker
	bash scripts/run-all.sh

web-bg: ## Start web fullstack in background (silent)
	@echo "Starting web fullstack in background..."
	$(call check_port,$(BACKEND_PORT))
	@cd frontend && $(NPM) run build >/dev/null 2>&1
	@MQTT_BROKER_HOST=$(MQTT_BROKER_HOST) MQTT_BROKER_PORT=$(MQTT_BROKER_PORT) \
	BACKEND_HOST=$(BACKEND_HOST) BACKEND_PORT=$(BACKEND_PORT) \
		$(PYTHON) -m backend.app > backend.log 2>&1 &
	@echo $$! > web_backend.pid
	@echo "Web fullstack started in background"
	@echo "  URL: http://$(BACKEND_HOST):$(BACKEND_PORT)"

web-logs: ## View all web stack logs in real-time
	@echo "📋  Tailing all logs (Ctrl+C to exit)..."
	@tail -f backend.log firmware.log web_startup.log 2>/dev/null || \
		echo "⚠️   Some log files not found. Available logs:"; \
		ls -la *.log 2>/dev/null || true

web-test: ## Run quick test against running web stack
	@echo "🧪  Testing web stack..."
	@echo "$(shell date '+%Y-%m-%d %H:%M:%S') - Starting web tests" >> web_startup.log
	@curl -sf http://$(BACKEND_HOST):$(BACKEND_PORT)/api/status >/dev/null 2>&1 && \
		(echo "✅  API status: OK"; echo "$(shell date '+%Y-%m-%d %H:%M:%S') - API status OK" >> web_startup.log) || \
		(echo "❌  API status: Failed"; echo "$(shell date '+%Y-%m-%d %H:%M:%S') - API status Failed" >> web_startup.log; exit 1)
	@curl -sf http://$(BACKEND_HOST):$(BACKEND_PORT) >/dev/null 2>&1 && \
		(echo "✅  Frontend: OK"; echo "$(shell date '+%Y-%m-%d %H:%M:%S') - Frontend OK" >> web_startup.log) || \
		(echo "❌  Frontend: Failed"; echo "$(shell date '+%Y-%m-%d %H:%M:%S') - Frontend Failed" >> web_startup.log; exit 1)
	@echo "✅  All tests passed!"

web-stop: ## Stop web fullstack (firmware + backend + MQTT broker)
	@echo "Stopping web fullstack..."
	@echo "  [1/5] firmware.pid..."
	@if [ -f firmware.pid ]; then \
		PID=$$(cat firmware.pid | tr -d '[:space:]'); \
		echo "  firmware.pid contains: '$$PID'"; \
		if echo "$$PID" | grep -qE '^[0-9]+$$'; then \
			echo "  kill -9 $$PID"; \
			kill -9 $$PID 2>/dev/null && echo "  Firmware stopped (PID $$PID)" || echo "  PID $$PID already gone"; \
		else \
			echo "  Invalid PID, skipping kill"; \
		fi; \
		rm -f firmware.pid; \
	else \
		echo "  firmware.pid not found"; \
	fi
	@echo "  [2/5] pkill firmware.main..."
	@pkill -9 -f 'firmware.main' 2>/dev/null && echo "  killed firmware.main" || echo "  firmware.main not running"
	@echo "  [3/5] web_backend.pid..."
	@if [ -f web_backend.pid ]; then \
		PID=$$(cat web_backend.pid | tr -d '[:space:]'); \
		echo "  web_backend.pid contains: '$$PID'"; \
		if echo "$$PID" | grep -qE '^[0-9]+$$'; then \
			echo "  kill -9 $$PID"; \
			kill -9 $$PID 2>/dev/null && echo "  Backend stopped (PID $$PID)" || echo "  PID $$PID already gone"; \
		else \
			echo "  Invalid PID, skipping kill"; \
		fi; \
		rm -f web_backend.pid; \
	else \
		echo "  web_backend.pid not found"; \
	fi
	@echo "  [4/5] kill port $(BACKEND_PORT)..."
	@PIDS=$$(lsof -ti :$(BACKEND_PORT) 2>/dev/null); \
	if [ -n "$$PIDS" ]; then \
		echo "  port $(BACKEND_PORT) used by: $$PIDS"; \
		echo "$$PIDS" | xargs -r kill -9 2>/dev/null || true; \
	else \
		echo "  port $(BACKEND_PORT) free"; \
	fi
	@pkill -9 -f 'backend.app' 2>/dev/null && echo "  killed backend.app" || echo "  backend.app not running"
	@echo "  [5/5] stopping mosquitto..."
	@docker compose -f docker-compose.fullstack.yml stop mosquitto 2>/dev/null || \
		docker stop mosquitto-tic249 2>/dev/null || \
		echo "  MQTT broker stopped or not running"
	@echo "Web fullstack stopped"

# ── Legacy web panel ───────────────────────────────────────
web-legacy: $(VENV)/bin/activate ## Start legacy Flask web panel (port 5000)
	@echo "Starting legacy web panel on http://localhost:5000"
	$(PYTHON) web_panel.py

web-legacy-bg: $(VENV)/bin/activate ## Start legacy web panel in background
	$(PYTHON) web_panel.py &
	@echo $$! > web_panel.pid

web-legacy-stop: ## Stop legacy web panel
	@pkill -f 'python web_panel.py' 2>/dev/null && echo "Web panel stopped" || echo "Not running"
	@rm -f web_panel.pid

cli: $(VENV)/bin/activate ## Run legacy CLI controller
	$(PYTHON) tic_t249_controller.py $(ARGS)

shell: ## Run legacy bash CLI shell
	bash cli_shell.sh

status: $(VENV)/bin/activate ## Check motor status (legacy)
	$(PYTHON) tic_t249_controller.py status

home: $(VENV)/bin/activate ## Perform homing (legacy)
	$(PYTHON) tic_t249_controller.py home-reverse

# ── Testing ─────────────────────────────────────────────────
test: $(VENV)/bin/activate ## Run unit tests
	$(PYTHON) -m pytest tests/ -v -k "not e2e"

test-e2e: $(VENV)/bin/activate ## Run E2E tests for legacy web panel (port 5000)
	$(PYTHON) -m pytest tests/e2e/test_web_panel.py -v

test-e2e-new: $(VENV)/bin/activate ## Run E2E tests for new React frontend (auto-start/stop server)
	@echo "Starting web server for E2E tests..."
	$(call check_port,8008)
	@cd frontend && npm run build 2>/dev/null || true
	@MQTT_BROKER_HOST=$(MQTT_BROKER_HOST) MQTT_BROKER_PORT=$(MQTT_BROKER_PORT) \
	BACKEND_HOST=$(BACKEND_HOST) BACKEND_PORT=8008 \
		$(PYTHON) -m backend.app > /tmp/backend_e2e.log 2>&1 &
	@echo $$! > /tmp/web_backend_e2e.pid
	@sleep 5
	@echo "Running E2E tests on http://localhost:8008..."
	@BASE_URL=http://localhost:8008 $(PYTHON) -m pytest tests/e2e/test_react_frontend.py -v --tb=short; \
	TEST_RESULT=$$?; \
	echo "Stopping test server..."; \
	if [ -f /tmp/web_backend_e2e.pid ]; then kill -9 $$(cat /tmp/web_backend_e2e.pid) 2>/dev/null || true; rm -f /tmp/web_backend_e2e.pid; fi; \
	PID=$$(lsof -ti :8008 2>/dev/null | head -1); \
	if [ -n "$$PID" ]; then kill -9 $$PID 2>/dev/null || true; fi; \
	exit $$TEST_RESULT

test-e2e-all: test-e2e test-e2e-new ## Run all E2E tests

test-integration: ## Run integration tests
	$(PYTHON) tests/test_integration.py

test-all: test test-integration ## Run all tests

test-auto: ## Test auto-connect functionality
	$(PYTHON) test_auto_connect.py

# ── Dev tools ───────────────────────────────────────────────
dev-install: $(VENV)/bin/activate ## Install with dev dependencies
	$(PIP) install -e ".[dev]"

format: $(VENV)/bin/activate ## Format code with black
	$(PYTHON) -m black *.py firmware/*.py backend/*.py

lint: $(VENV)/bin/activate ## Lint code with ruff
	$(PYTHON) -m ruff check *.py firmware/*.py backend/*.py

clean: ## Clean build artifacts
	rm -rf $(VENV) build/ dist/ *.egg-info/
	rm -rf frontend/node_modules frontend/dist
	rm -rf backend/logs/logs.txt
	rm -f web_panel.pid
	find . -type d -name __pycache__ -exec rm -rf {} + 2>/dev/null || true
	find . -type f -name "*.pyc" -delete 2>/dev/null || true
	@echo "Cleaned"

# ── Utility ───────────────────────────────────────────────
stop: ## Stop all services (alias for stack-stop)
	@$(MAKE) stack-stop || true
