# shellcheck shell=sh disable=SC2046,SC2091,SC2086,SC2155
# NOTE: $(VAR) in this file is MAKE syntax, not shell substitution.
export TARGET=x86_64-unknown-uefi
export PROFILE=debug
export OUT_DIR=target/$(TARGET)/$(PROFILE)
export ESP_DIR=esp
export KERNEL=$(OUT_DIR)/rsdos.efi
export BZIMAGE=$(ESP_DIR)/bzImage
export INITRD=$(ESP_DIR)/initramfs.cpio.gz
export BOOTLOADER=rsboot/rsboot.efi
export OVMF=/usr/share/edk2/x64/OVMF.4m.fd
export BOOT_EFI=$(ESP_DIR)/EFI/BOOT/BOOTX64.EFI
# Attach the single dd-able system image as the SATA drive (ide.0).
# Create/re-create with: make system-fresh   (or: ./scripts/mksystem.sh --force)
export SYSTEM_IMG ?= /tmp/system.img


# ---- Build ---------------------------------------------------------------

.PHONY: all run run-gui clean image debug release fmt bootloader boot-image system system-fresh inspect test-disk test-mouse test-gfx test-fault test-msg

release: PROFILE=release
release: export PROFILE=release
release: export OUT_DIR=target/$(TARGET)/release
release: CARGO_FLAGS=--release
release: all

# shellcheck disable=SC2034
CARGO_FLAGS=

$(OUT_DIR)/rsdos.efi: $(shell find rsnix shell rsdos -name '*.rs') Cargo.toml rsnix/Cargo.toml shell/Cargo.toml rsdos/Cargo.toml
	cargo build --package rsdos --target $(TARGET) $(CARGO_FLAGS)

$(BZIMAGE): $(KERNEL) | $(ESP_DIR)
	cp "$<" "$@"

$(ESP_DIR):
	mkdir -p $(ESP_DIR)

$(INITRD): | $(ESP_DIR)
	printf '' | gzip > "$@"

# ---- QEMU runners --------------------------------------------------------

run: all system
	qemu-system-x86_64 \
	  -bios $(OVMF) \
	  -drive file=$(SYSTEM_IMG),format=raw,if=none,id=disk \
	  -device ide-hd,drive=disk,bus=ide.0 \
	  -serial stdio \
	  -m 256M \
	  -machine q35 \
	  -cpu qemu64 \
	  -no-reboot \
	  -display none

run-gui: all system
	qemu-system-x86_64 \
	  -bios $(OVMF) \
	  -drive file=$(SYSTEM_IMG),format=raw,if=none,id=disk \
	  -device ide-hd,drive=disk,bus=ide.0 \
	  -serial stdio \
	  -m 256M \
	  -machine q35 \
	  -cpu qemu64 \
	  -no-reboot \
	  -vga std

# GDB stub on :1234
debug: all system
	qemu-system-x86_64 \
	  -bios $(OVMF) \
	  -drive file=$(SYSTEM_IMG),format=raw,if=none,id=disk \
	  -device ide-hd,drive=disk,bus=ide.0 \
	  -serial stdio \
	  -m 256M \
	  -machine q35 \
	  -cpu qemu64 \
	  -no-reboot \
	  -display none \
	  -s -S

# Boot from a raw disk image (delegates to boot-image.sh which builds the
# full chain if the image doesn't exist yet)
run-image: all

# ---- System image --------------------------------------------------------

# One dd-able FAT32 image: kernel + ESP + /etc + /bin + seed data.
# Stamp rule: rebuilt only when the kernel or this script changes — an
# up-to-date image is NEVER touched, so files written at runtime survive.
system:
	@if [ ! -f "$(SYSTEM_IMG)" ] || [ "$$(stat -c %Y $(BZIMAGE) 2>/dev/null || echo 0)" -gt "$$(stat -c %Y $(SYSTEM_IMG) 2>/dev/null || echo 0)" ]; then \
	  ./scripts/mksystem.sh --force "$(SYSTEM_IMG)"; \
	else \
	  echo "system image up to date: $(SYSTEM_IMG)"; \
	fi

# Re-create the system image from scratch (wipes runtime data).
system-fresh:
	./scripts/mksystem.sh --force "$(SYSTEM_IMG)"

# List the system image contents with mtools (requires mtools).
inspect:
	@command -v mdir >/dev/null 2>&1 || (echo "inspect needs mtools: sudo apt install mtools"; exit 1)
	@mdir -i "$(SYSTEM_IMG)" ::

# Full automated round trip: build -> boot -> shell commands -> poweroff
# -> fsck + mtools verification.
test-disk:
	./scripts/test-disk.sh

# Automated PS/2 mouse round trip: boot -> inject mouse_move/mouse_button
# via the monitor -> verify /dev/mouse + the `mouse` stream -> poweroff.
test-mouse:
	./scripts/test-mouse.sh

test-gfx:
	./scripts/test-gfx.sh

# Fault-diagnostics round trip: boot -> `fault` (deliberate page fault) ->
# verify the full dump (vec/err/rip/cr2/task) hits serial + screen -> halt.
test-fault:
	./scripts/test-fault.sh

# Automated scheduler message-queue round trip: msgrecv/send, real-input
# routing into a task's queue, queue-full boundary.
test-msg:
	./scripts/test-msg.sh

# ---- Full boot chain -----------------------------------------------------

# Build bootloader only (rsboot submodule)
bootloader:
	./scripts/build-bootloader.sh

# Build the full boot chain disk image (kernel + bootloader)
image: all
	./scripts/build-image.sh rs-dos.img

# Boot the full chain disk image (builds it first if needed)
boot-image: all
	./scripts/boot-image.sh rs-dos.img

# ---- Utilities -----------------------------------------------------------

fmt:
	cargo fmt

clean:
	cargo clean
	rm -rf $(ESP_DIR)

help:
	@echo "rs-dos — Make targets"
	@echo ""
	@echo "  make                build kernel + ESP (default)"
	@echo "  make release        build with --release (smaller binary)"
	@echo "  make bootloader     build rsboot from source"
	@echo "  make image          build full chain disk image (bootloader + kernel)"
	@echo "  make boot-image     build + boot full chain via QEMU"
	@echo "  make run            QEMU serial console (direct boot, no bootloader)"
	@echo "  make system         create the system image if stale/missing (/tmp/system.img)"
	@echo "  make system-fresh   re-create the system image (wipes runtime data)"
	@echo "  make inspect        list system image contents (mtools)"
	@echo "  make test-disk      automated disk round trip (build->boot->fsck)"
	@echo "  make clean          remove build artifacts"
	@echo "  make fmt            format Rust source"
	@echo "  ./scripts/mksystem.sh          build the dd-able system image"
	@echo "  ./scripts/boot.sh              quick direct boot (dev loop)"
	@echo "  ./scripts/mkdisk.sh            create/re-format the data disk"
	@echo "  ./scripts/test-disk.sh         automated disk round trip"
	@echo "  ./scripts/sendkeys.py          type into QEMU via the monitor"
	@echo "  ./scripts/boot-image.sh        boot full chain (builds if needed)"
	@echo "  ./scripts/build-image.sh       build full chain disk image"
	@echo "  ./scripts/build-bootloader.sh  build rsboot from source"
	@echo "  ./scripts/qemu.sh              flexible QEMU launcher"
	@echo "  ./scripts/debug-kernel.py      GDB plugin (attach after 'make debug')"
