# ============================================================
# Pentest-MCP - Makefile Dinámico
# ============================================================
# Este Makefile lee dinámicamente los YAMLs para generar targets
# No hay hardcodeo de nombres de herramientas
# ============================================================

.PHONY: help
.DEFAULT_GOAL := help


# ===================================
# Normalización automática de finales de línea (CRLF → LF)
# ===================================
# Este bloque se ejecuta SIEMPRE antes de cualquier target de make.
# Evita errores por archivos con formato Windows (\r\n).
# Se ejecuta en silencio y omite binarios.

.PHONY: normalize
normalize:
	@find . -type f \
	  ! -name "*.png" \
	  ! -name "*.jpg" \
	  ! -name "*.jpeg" \
	  ! -name "*.gif" \
	  ! -name "*.pdf" \
	  ! -name "*.zip" \
	  ! -name "*.tar.gz" \
	  ! -name "*.exe" \
	  -exec dos2unix {} + >/dev/null 2>&1 || true

# === Hook global para ejecutar "normalize" antes de cualquier target ===
# Si ejecutas "make build-all" o "make test", primero se ejecuta normalize.
MAKECMDGOALS ?= help
$(MAKECMDGOALS): normalize


# ===================================
# Variables de configuración
# ===================================
PYTHON := python3
COMPOSE := docker-compose
DOCKER := docker

# Directorios
TOOLS_DIR := .
DOCKERFILES_DIR := ./dockerfiles
SCRIPTS_DIR := ./scripts

# Colores para output
GREEN := \033[0;32m
YELLOW := \033[1;33m
RED := \033[0;31m
NC := \033[0m

# ===================================
# Auto-discovery de herramientas desde YAMLs
# ===================================

# Extraer lista de herramientas con config Docker
TOOLS_WITH_DOCKER := $(shell $(PYTHON) -c "import yaml, sys; \
	from pathlib import Path; \
	tools = []; \
	[tools.append(yaml.safe_load(open(f))['name']) \
	 for f in Path('$(TOOLS_DIR)').rglob('*.yaml') \
	 if yaml.safe_load(open(f)).get('docker')]; \
	print(' '.join(tools))" 2>/dev/null || echo "")

# Lista de todas las imágenes esperadas
EXPECTED_IMAGES := pentest-kali-base pentest-mcp-app $(foreach tool,$(TOOLS_WITH_DOCKER),pentest-$(tool))

# ===================================
# Help / Documentación
# ===================================

help: ## Muestra esta ayuda
	@echo ""
	@echo "$(GREEN)╔════════════════════════════════════════════╗$(NC)"
	@echo "$(GREEN)║   Pentest-MCP - Dynamic Makefile          ║$(NC)"
	@echo "$(GREEN)╚════════════════════════════════════════════╝$(NC)"
	@echo ""
	@echo "$(YELLOW)📦 Tools detectadas desde YAML:$(NC)"
	@echo "   $(TOOLS_WITH_DOCKER)"
	@echo ""
	@echo "$(YELLOW)Comandos disponibles:$(NC)"
	@echo ""
	@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | \
		awk 'BEGIN {FS = ":.*?## "}; {printf "  $(GREEN)%-20s$(NC) %s\n", $$1, $$2}'
	@echo ""



# ===================================
# Setup inicial
# ===================================

setup: ## Crear directorios necesarios como (wordlist y results)
	@echo "$(GREEN)📁 Creando directorios...$(NC)"
	mkdir -p wordlists results $(DOCKERFILES_DIR)
	@echo "$(GREEN)✅ Setup completo$(NC)"

# ===================================
# Docker Images - Construcción Dinámica
# ===================================

.PHONY: build-base
build-base: ## Construir imagen base de Kali
	@echo "$(YELLOW)🔨 Construyendo imagen base...$(NC)"
	$(DOCKER) build -t pentest-kali-base:latest -f $(DOCKERFILES_DIR)/Dockerfile.kali-base $(DOCKERFILES_DIR)
	@echo "$(GREEN)✅ Imagen base construida$(NC)"

.PHONY: build-app
build-app: ## Construir imagen de la aplicación principal (FastAPI / MCP)
	@echo "$(YELLOW)🔨 Construyendo imagen de la aplicación Pentest-MCP...$(NC)"
	$(DOCKER) build -t pentest-mcp-app:latest -f Dockerfile.app .
	@echo "$(GREEN)✅ Imagen pentest-mcp-app construida correctamente$(NC)"


.PHONY: build-tools
build-tools: build-base ## Construir todas las imágenes de herramientas
	@echo "$(YELLOW)🔨 Construyendo herramientas: $(TOOLS_WITH_DOCKER)$(NC)"
	@for tool in $(TOOLS_WITH_DOCKER); do \
		echo "$(YELLOW)  • Construyendo $$tool...$(NC)"; \
		$(DOCKER) build -t pentest-$$tool:latest \
			-f $(DOCKERFILES_DIR)/Dockerfile.$$tool \
			$(DOCKERFILES_DIR) || exit 1; \
		echo "$(GREEN)  ✅ pentest-$$tool construido$(NC)"; \
	done
	@echo "$(GREEN)✅ Todas las herramientas construidas$(NC)"

.PHONY: build-all
build-all: build-base build-app build-tools ## Construir todas las imágenes (base + app + tools)
	@echo "$(GREEN)✅ Build completo$(NC)"

# Target dinámico para construir una herramienta específica
.PHONY: build-%
build-%: build-base ## Construir una herramienta específica (ej: make build-nmap)
	@tool=$$(echo $* | sed 's/^build-//'); \
	if echo "$(TOOLS_WITH_DOCKER)" | grep -q "$$tool"; then \
		echo "$(YELLOW)🔨 Construyendo $$tool...$(NC)"; \
		$(DOCKER) build -t pentest-$$tool:latest \
			-f $(DOCKERFILES_DIR)/Dockerfile.$$tool \
			$(DOCKERFILES_DIR); \
		echo "$(GREEN)✅ pentest-$$tool construido$(NC)"; \
	else \
		echo "$(RED)❌ Herramienta '$$tool' no encontrada en YAMLs$(NC)"; \
		echo "$(YELLOW)Herramientas disponibles: $(TOOLS_WITH_DOCKER)$(NC)"; \
		exit 1; \
	fi

# ===================================
# Verificación de imágenes
# ===================================

.PHONY: check-images
check-images: ## Verificar qué imágenes están construidas
	@echo "$(YELLOW)🔍 Verificando imágenes Docker...$(NC)"
	@echo ""
	@for img in $(EXPECTED_IMAGES); do \
		if $(DOCKER) images -q $$img:latest 2>/dev/null | grep -q .; then \
			echo "$(GREEN)✅ $$img$(NC)"; \
		else \
			echo "$(RED)❌ $$img (no construida)$(NC)"; \
		fi; \
	done
	@echo ""
	@built=$$(for img in $(EXPECTED_IMAGES); do \
		$(DOCKER) images -q $$img:latest 2>/dev/null | grep -q . && echo 1; \
	done | wc -l); \
	total=$$(echo $(EXPECTED_IMAGES) | wc -w); \
	echo "$(YELLOW)Total: $$built/$$total imágenes construidas$(NC)"

.PHONY: list-images
list-images: ## Listar todas las imágenes pentest
	@echo "$(YELLOW)📦 Imágenes Pentest:$(NC)"
	@$(DOCKER) images | grep pentest- || echo "$(RED)No hay imágenes pentest$(NC)"

# ===================================
# Limpieza
# ===================================

.PHONY: clean-images
clean-images: ## Eliminar todas las imágenes pentest
	@echo "$(RED)🗑️  Eliminando imágenes...$(NC)"
	@for img in $(EXPECTED_IMAGES); do \
		$(DOCKER) rmi $$img:latest 2>/dev/null || true; \
	done
	@echo "$(GREEN)✅ Imágenes eliminadas$(NC)"

.PHONY: clean-containers
clean-containers: ## Eliminar contenedores pentest
	@echo "$(RED)🗑️  Eliminando contenedores...$(NC)"
	$(DOCKER) ps -a | grep pentest | awk '{print $$1}' | xargs -r $(DOCKER) rm -f
	@echo "$(GREEN)✅ Contenedores eliminados$(NC)"

.PHONY: clean
clean: clean-containers ## Limpieza completa (contenedores + imágenes)
	@echo "$(GREEN)✅ Limpieza completa$(NC)"

# ===================================
# Docker Compose
# ===================================

.PHONY: up
up: ## Iniciar servicios con docker-compose
	$(COMPOSE) up -d
	@echo "$(GREEN)✅ Servicios iniciados$(NC)"
	@echo "$(YELLOW)REST API: http://localhost:8085$(NC)"
	@echo "$(YELLOW)MCP Server: http://localhost:8090$(NC)"

.PHONY: down
down: ## Detener servicios
	$(COMPOSE) down
	@echo "$(GREEN)✅ Servicios detenidos$(NC)"

.PHONY: logs
logs: ## Ver logs de los servicios
	$(COMPOSE) logs -f

.PHONY: restart
restart: ## Reiniciar servicios (rebuild app si hay cambios)
	$(COMPOSE) up -d --build pentest_app
	@echo "$(GREEN)✅ Servicios reiniciados$(NC)"

# ===================================
# Testing
# ===================================

.PHONY: test
test: ## Ejecutar tests del sistema (usa .env)
	@if [ -f .env ]; then \
		export $$(grep -v '^#' .env | xargs); \
	fi; \
	if [ -f $(SCRIPTS_DIR)/test_system.sh ]; then \
		bash $(SCRIPTS_DIR)/test_system.sh; \
	else \
		echo "$(RED)❌ test_system.sh no encontrado$(NC)"; \
	fi


.PHONY: test-api
test-api: ## Test rápido de la API REST
	@echo "$(YELLOW)🧪 Testing REST API...$(NC)"
	@curl -s http://localhost:8085/health | jq . || echo "$(RED)❌ API no responde$(NC)"
	@curl -s http://localhost:8085/tools | jq '.total_tools' || echo "$(RED)❌ /tools falla$(NC)"

# ===================================
# Utilidades YAML
# ===================================

.PHONY: validate-yaml
validate-yaml: ## Validar sintaxis de todos los YAMLs
	@echo "$(YELLOW)🔍 Validando YAMLs...$(NC)"
	@$(PYTHON) $(SCRIPTS_DIR)/validate_yaml.py $(TOOLS_DIR)

.PHONY: fix-yaml-paths
fix-yaml-paths: ## Corregir rutas Docker en YAMLs
	@echo "$(YELLOW)🔧 Corrigiendo rutas en YAMLs...$(NC)"
	@if [ -f $(SCRIPTS_DIR)/fix_yaml_paths.py ]; then \
		$(PYTHON) $(SCRIPTS_DIR)/fix_yaml_paths.py --dir $(TOOLS_DIR); \
	else \
		echo "$(RED)❌ fix_yaml_paths.py no encontrado$(NC)"; \
	fi

.PHONY: show-docker-config
show-docker-config: ## Mostrar configuración Docker de los YAMLs
	@echo "$(YELLOW)📦 Configuración Docker en YAMLs:$(NC)"
	@echo ""
	@$(PYTHON) $(SCRIPTS_DIR)/show_docker_config.py $(TOOLS_DIR)

# ===================================
# Desarrollo
# ===================================

.PHONY: dev
dev: ## Iniciar en modo desarrollo
	$(PYTHON) server.py

.PHONY: dev-mcp
dev-mcp: ## Iniciar MCP server standalone
	TRANSPORT=stdio $(PYTHON) mcp_server.py

# ===================================
# Información del sistema
# ===================================

.PHONY: info
info: ## Mostrar información del sistema
	@echo ""
	@echo "$(GREEN)╔════════════════════════════════════════════╗$(NC)"
	@echo "$(GREEN)║   Pentest-MCP - System Info               ║$(NC)"
	@echo "$(GREEN)╚════════════════════════════════════════════╝$(NC)"
	@echo ""
	@echo "$(YELLOW)📦 Herramientas detectadas:$(NC)"
	@echo "   $(TOOLS_WITH_DOCKER)"
	@echo ""
	@echo "$(YELLOW)🐳 Docker:$(NC)"
	@$(DOCKER) --version
	@echo ""
	@echo "$(YELLOW)🐍 Python:$(NC)"
	@$(PYTHON) --version
	@echo ""
	@echo "$(YELLOW)📂 Estructura:$(NC)"
	@echo "   Tools dir: $(TOOLS_DIR)"
	@echo "   Dockerfiles: $(DOCKERFILES_DIR)"
	@echo "   Scripts: $(SCRIPTS_DIR)"
	@echo ""