# BookFlow Metadata Engine Makefile
# Работает под Windows (PowerShell), Linux и macOS

APP_NAME    := bookflow-metadata
BUILD_DIR   := build
CMD_PATH    := ./cmd/bookflow-metadata
GO          := go
GOFLAGS     := -trimpath

# Директория результатов (для clean-results)
OUTPUT_DIR  := ./result

# ── Параметры Gitea для CI/CD-команд ─────────────────────────────────────────
# Переопределить через env или CLI: make release-tag GITEA_URL=https://...
GITEA_URL   ?= https://github.dfv24.com
GITEA_REPO  ?= fofanov.dmitry/bookflow-metadata
GIT_TOKEN   ?=
GITEA_TOKEN ?=

# ============================================================================
#  Определяем оболочку по платформе
# ============================================================================

ifeq ($(OS),Windows_NT)
    SHELL         = powershell.exe
    .SHELLFLAGS   = -NoProfile -ExecutionPolicy Bypass -Command
    GIT_VERSION  := $(shell try { git describe --tags --abbrev=0 2>$$null } catch { '' })
    BUILD_DATE   := $(shell Get-Date -Format 'yyyy-MM-ddTHH:mm:ssZ')
    GIT_COMMIT   := $(shell try { git rev-parse --short HEAD 2>$$null } catch { 'unknown' })
    GO_VERSION   := $(shell try { (go env GOVERSION) -replace '^go','' } catch { 'unknown' })
else
    SHELL        := /bin/sh
    GIT_VERSION  := $(shell git describe --tags --abbrev=0 2>/dev/null)
    BUILD_DATE   := $(shell date -u +'%Y-%m-%dT%H:%M:%SZ' 2>/dev/null || echo unknown)
    GIT_COMMIT   := $(shell git rev-parse --short HEAD 2>/dev/null || echo unknown)
    GO_VERSION   := $(shell go env GOVERSION 2>/dev/null | sed 's/^go//' || echo unknown)
endif

VERSION     := $(if $(GIT_VERSION),$(patsubst v%,%,$(GIT_VERSION)),dev)
LDFLAGS     := -s -w -X main.version=$(VERSION)

# ============================================================================
#  Основные команды
# ============================================================================

.PHONY: all build run clean test lint deps tidy fmt vet help clean-results ensure-build-dir wiki-update clean-env
.PHONY: release release-prepare release-tag release-tag-delete ci-release ci-check release-local

## Сборка + тесты (цель по умолчанию при явном вызове make all)
all: build vet

# ============================================================================
#  Вспомогательная цель: создать build/ если не существует
# ============================================================================

ifeq ($(OS),Windows_NT)
ensure-build-dir:
	New-Item -ItemType Directory -Force '$(BUILD_DIR)' | Out-Null
else
ensure-build-dir:
	@mkdir -p $(BUILD_DIR)
endif

## Сброс переменных кросс-компиляции (GOOS/GOARCH/GOARM/GOMIPS)
## Запускать после ручной кросс-компиляции в PowerShell: make clean-env
ifeq ($(OS),Windows_NT)
clean-env:
	Remove-Item Env:GOOS,Env:GOARCH,Env:GOARM,Env:GOMIPS -ErrorAction SilentlyContinue; Write-Host '>>> Переменные кросс-компиляции сброшены (GOOS/GOARCH/GOARM/GOMIPS)'
else
clean-env:
	@unset GOOS GOARCH GOARM GOMIPS; echo '>>> Переменные кросс-компиляции сброшены (GOOS/GOARCH/GOARM/GOMIPS)'
endif

## Сборка для текущей платформы
ifeq ($(OS),Windows_NT)
build: ensure-build-dir
	$(info >>> Сборка $(APP_NAME) для текущей платформы...)
	$$env:GOOS=''; $$env:GOARCH=''; Remove-Item Env:GOARM,Env:GOMIPS -ErrorAction SilentlyContinue; $(GO) build $(GOFLAGS) -ldflags '$(LDFLAGS)' -o $(BUILD_DIR)/$(APP_NAME).exe $(CMD_PATH)
	$(info >>> Готово: $(BUILD_DIR)/$(APP_NAME).exe)
else
build: ensure-build-dir
	$(info >>> Сборка $(APP_NAME) для текущей платформы...)
	$(GO) build $(GOFLAGS) -ldflags "$(LDFLAGS)" -o $(BUILD_DIR)/$(APP_NAME) $(CMD_PATH)
	$(info >>> Готово: $(BUILD_DIR)/$(APP_NAME))
endif

## Сборка для Windows
ifeq ($(OS),Windows_NT)
build-windows-current:
	$(info >>> Сборка $(APP_NAME).exe для Windows...)
	$$env:GOOS='windows'; $$env:GOARCH='amd64'; Remove-Item Env:GOARM,Env:GOMIPS -ErrorAction SilentlyContinue; $(GO) build $(GOFLAGS) -ldflags '$(LDFLAGS)' -o $(APP_NAME).exe $(CMD_PATH)
	$(info >>> Готово: $(APP_NAME).exe)
else
build-windows-current:
	$(info >>> Сборка $(APP_NAME).exe для Windows...)
	$(GO) build $(GOFLAGS) -ldflags "$(LDFLAGS)" -o $(APP_NAME).exe $(CMD_PATH)
	$(info >>> Готово: $(APP_NAME).exe)
endif

## Запуск без сборки (с параметрами по умолчанию)
ifeq ($(OS),Windows_NT)
run:
	$(info >>> Запуск $(APP_NAME)...)
	$(GO) run $(CMD_PATH) -workers 8 -timeout 60m
else
run:
	$(info >>> Запуск $(APP_NAME)...)
	$(GO) run $(CMD_PATH) -workers 8 -timeout 60m
endif

## Запуск с собственными параметрами (пример: make run-custom ARGS="-workers 4 -timeout 30")
ifeq ($(OS),Windows_NT)
run-custom:
	$(info >>> Запуск с параметрами: $(ARGS)...)
	$$env:GOOS=''; $$env:GOARCH=''; $(GO) run $(CMD_PATH) $(ARGS)
else
run-custom:
	$(info >>> Запуск с параметрами: $(ARGS)...)
	$(GO) run $(CMD_PATH) $(ARGS)
endif

## Запуск unit-тестов
ifeq ($(OS),Windows_NT)
test:
	$(info >>> Запуск тестов...)
	$$env:GOOS=''; $$env:GOARCH=''; $(GO) test ./... -v -race -count=1
else
test:
	$(info >>> Запуск тестов...)
	$(GO) test ./... -v -race -count=1
endif

## Запуск тестов с покрытием
ifeq ($(OS),Windows_NT)
test-cover:
	$(info >>> Запуск тестов с покрытием...)
	$$env:GOOS=''; $$env:GOARCH=''; $(GO) test ./... -v -race -coverprofile=coverage.out
	$(GO) tool cover -html=coverage.out -o coverage.html
	$(info >>> Отчёт: coverage.html)
else
test-cover:
	$(info >>> Запуск тестов с покрытием...)
	$(GO) test ./... -v -race -coverprofile=coverage.out
	$(GO) tool cover -html=coverage.out -o coverage.html
	$(info >>> Отчёт: coverage.html)
endif

## Установка зависимостей
deps:
	$(info >>> Установка зависимостей...)
	$(GO) mod download

## Очистка и обновление go.mod
tidy:
	$(GO) mod tidy

## Форматирование кода
fmt:
	$(info >>> Форматирование кода...)
	$(GO) fmt ./...

## Статический анализ
vet:
	$(info >>> Статический анализ...)
	$(GO) vet ./...

## Линтер (требуется golangci-lint)
ifeq ($(OS),Windows_NT)
lint:
	$(info >>> Линтинг...)
	@if (Get-Command golangci-lint -ErrorAction SilentlyContinue) { golangci-lint run ./... } else { $(info golangci-lint не установлен: go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest) }
else
lint:
	$(info >>> Линтинг...)
	@command -v golangci-lint >/dev/null 2>&1 && golangci-lint run ./... || echo "golangci-lint не установлен: go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest"
endif

## Очистка артефактов сборки
ifeq ($(OS),Windows_NT)
clean:
	$(info >>> Очистка артефактов сборки...)
	-Remove-Item -Recurse -Force '$(BUILD_DIR)' -ErrorAction SilentlyContinue
	-Remove-Item -Force '$(APP_NAME).exe' -ErrorAction SilentlyContinue
	-Remove-Item -Force 'coverage.out','coverage.html' -ErrorAction SilentlyContinue
	$(info >>> Готово)
else
clean:
	$(info >>> Очистка артефактов сборки...)
	@rm -rf $(BUILD_DIR) coverage.out coverage.html $(APP_NAME)
	$(info >>> Готово)
endif

## Очистка результатов работы программы
ifeq ($(OS),Windows_NT)
clean-results:
	$(info >>> Очистка директории результатов...)
	-Remove-Item -Recurse -Force '$(OUTPUT_DIR)' -ErrorAction SilentlyContinue
	New-Item -ItemType Directory -Force '$(OUTPUT_DIR)' | Out-Null
	$(info >>> Готово)
else
clean-results:
	$(info >>> Очистка директории результатов...)
	@rm -rf $(OUTPUT_DIR) && mkdir -p $(OUTPUT_DIR)
	$(info >>> Готово)
endif

## Полная очистка (артефакты + результаты)
clean-all: clean clean-results


# ============================================================================
#  Кросс-компиляция: все платформы
# ============================================================================

.PHONY: build-all build-linux build-darwin build-windows build-arm build-freebsd build-openbsd build-netbsd

## Сборка под ВСЕ платформы
build-all: clean ensure-build-dir build-linux build-darwin build-windows build-arm build-freebsd build-openbsd build-netbsd
	$(info )
	$(info =========================================)
	$(info   Сборка завершена для всех платформ)
	$(info =========================================)

	$(info )

# ============================================================================
#  Linux
# ============================================================================

build-linux: build-linux-amd64 build-linux-386 build-linux-arm64 build-linux-arm7

ifeq ($(OS),Windows_NT)
build-linux-amd64:
	$(info >>> Linux amd64...)
	$$env:GOOS='linux'; $$env:GOARCH='amd64'; Remove-Item Env:GOARM,Env:GOMIPS -ErrorAction SilentlyContinue; $(GO) build $(GOFLAGS) -ldflags '$(LDFLAGS)' -o $(BUILD_DIR)/$(APP_NAME)-linux-amd64 $(CMD_PATH)
else
build-linux-amd64:
	$(info >>> Linux amd64...)
	GOOS=linux GOARCH=amd64 $(GO) build $(GOFLAGS) -ldflags "$(LDFLAGS)" -o $(BUILD_DIR)/$(APP_NAME)-linux-amd64 $(CMD_PATH)
endif

ifeq ($(OS),Windows_NT)
build-linux-386:
	$(info >>> Linux 386...)
	$$env:GOOS='linux'; $$env:GOARCH='386'; Remove-Item Env:GOARM,Env:GOMIPS -ErrorAction SilentlyContinue; $(GO) build $(GOFLAGS) -ldflags '$(LDFLAGS)' -o $(BUILD_DIR)/$(APP_NAME)-linux-386 $(CMD_PATH)
else
build-linux-386:
	$(info >>> Linux 386...)
	GOOS=linux GOARCH=386 $(GO) build $(GOFLAGS) -ldflags "$(LDFLAGS)" -o $(BUILD_DIR)/$(APP_NAME)-linux-386 $(CMD_PATH)
endif

ifeq ($(OS),Windows_NT)
build-linux-arm64:
	$(info >>> Linux arm64...)
	$$env:GOOS='linux'; $$env:GOARCH='arm64'; Remove-Item Env:GOARM,Env:GOMIPS -ErrorAction SilentlyContinue; $(GO) build $(GOFLAGS) -ldflags '$(LDFLAGS)' -o $(BUILD_DIR)/$(APP_NAME)-linux-arm64 $(CMD_PATH)
else
build-linux-arm64:
	$(info >>> Linux arm64...)
	GOOS=linux GOARCH=arm64 $(GO) build $(GOFLAGS) -ldflags "$(LDFLAGS)" -o $(BUILD_DIR)/$(APP_NAME)-linux-arm64 $(CMD_PATH)
endif

ifeq ($(OS),Windows_NT)
build-linux-arm7:
	$(info >>> Linux armv7...)
	$$env:GOOS='linux'; $$env:GOARCH='arm'; $$env:GOARM='7'; Remove-Item Env:GOMIPS -ErrorAction SilentlyContinue; $(GO) build $(GOFLAGS) -ldflags '$(LDFLAGS)' -o $(BUILD_DIR)/$(APP_NAME)-linux-armv7 $(CMD_PATH)
else
build-linux-arm7:
	$(info >>> Linux armv7...)
	GOOS=linux GOARCH=arm GOARM=7 $(GO) build $(GOFLAGS) -ldflags "$(LDFLAGS)" -o $(BUILD_DIR)/$(APP_NAME)-linux-armv7 $(CMD_PATH)
endif


# ============================================================================
#  macOS
# ============================================================================

build-darwin: build-darwin-amd64 build-darwin-arm64

ifeq ($(OS),Windows_NT)
build-darwin-amd64:
	$(info >>> macOS amd64 (Intel)...)
	$$env:GOOS='darwin'; $$env:GOARCH='amd64'; Remove-Item Env:GOARM,Env:GOMIPS -ErrorAction SilentlyContinue; $(GO) build $(GOFLAGS) -ldflags '$(LDFLAGS)' -o $(BUILD_DIR)/$(APP_NAME)-darwin-amd64 $(CMD_PATH)
else
build-darwin-amd64:
	$(info >>> macOS amd64 (Intel)...)
	GOOS=darwin GOARCH=amd64 $(GO) build $(GOFLAGS) -ldflags "$(LDFLAGS)" -o $(BUILD_DIR)/$(APP_NAME)-darwin-amd64 $(CMD_PATH)
endif

ifeq ($(OS),Windows_NT)
build-darwin-arm64:
	$(info >>> macOS arm64 (Apple Silicon)...)
	$$env:GOOS='darwin'; $$env:GOARCH='arm64'; Remove-Item Env:GOARM,Env:GOMIPS -ErrorAction SilentlyContinue; $(GO) build $(GOFLAGS) -ldflags '$(LDFLAGS)' -o $(BUILD_DIR)/$(APP_NAME)-darwin-arm64 $(CMD_PATH)
else
build-darwin-arm64:
	$(info >>> macOS arm64 (Apple Silicon)...)
	GOOS=darwin GOARCH=arm64 $(GO) build $(GOFLAGS) -ldflags "$(LDFLAGS)" -o $(BUILD_DIR)/$(APP_NAME)-darwin-arm64 $(CMD_PATH)
endif


# ============================================================================
#  Windows
# ============================================================================

build-windows: build-windows-amd64 build-windows-386 build-windows-arm64

ifeq ($(OS),Windows_NT)
build-windows-amd64:
	$(info >>> Windows amd64...)
	$$env:GOOS='windows'; $$env:GOARCH='amd64'; Remove-Item Env:GOARM,Env:GOMIPS -ErrorAction SilentlyContinue; $(GO) build $(GOFLAGS) -ldflags '$(LDFLAGS)' -o $(BUILD_DIR)/$(APP_NAME)-windows-amd64.exe $(CMD_PATH)
else
build-windows-amd64:
	$(info >>> Windows amd64...)
	GOOS=windows GOARCH=amd64 $(GO) build $(GOFLAGS) -ldflags "$(LDFLAGS)" -o $(BUILD_DIR)/$(APP_NAME)-windows-amd64.exe $(CMD_PATH)
endif

ifeq ($(OS),Windows_NT)
build-windows-386:
	$(info >>> Windows 386...)
	$$env:GOOS='windows'; $$env:GOARCH='386'; Remove-Item Env:GOARM,Env:GOMIPS -ErrorAction SilentlyContinue; $(GO) build $(GOFLAGS) -ldflags '$(LDFLAGS)' -o $(BUILD_DIR)/$(APP_NAME)-windows-386.exe $(CMD_PATH)
else
build-windows-386:
	$(info >>> Windows 386...)
	GOOS=windows GOARCH=386 $(GO) build $(GOFLAGS) -ldflags "$(LDFLAGS)" -o $(BUILD_DIR)/$(APP_NAME)-windows-386.exe $(CMD_PATH)
endif

ifeq ($(OS),Windows_NT)
build-windows-arm64:
	$(info >>> Windows arm64...)
	$$env:GOOS='windows'; $$env:GOARCH='arm64'; Remove-Item Env:GOARM,Env:GOMIPS -ErrorAction SilentlyContinue; $(GO) build $(GOFLAGS) -ldflags '$(LDFLAGS)' -o $(BUILD_DIR)/$(APP_NAME)-windows-arm64.exe $(CMD_PATH)
else
build-windows-arm64:
	$(info >>> Windows arm64...)
	GOOS=windows GOARCH=arm64 $(GO) build $(GOFLAGS) -ldflags "$(LDFLAGS)" -o $(BUILD_DIR)/$(APP_NAME)-windows-arm64.exe $(CMD_PATH)
endif


# ============================================================================
#  ARM / Embedded
# ============================================================================

build-arm: build-arm-mips build-arm-mipsle build-arm-riscv64

ifeq ($(OS),Windows_NT)
build-arm-mips:
	$(info >>> MIPS (big-endian)...)
	$$env:GOOS='linux'; $$env:GOARCH='mips'; $$env:GOMIPS='softfloat'; Remove-Item Env:GOARM -ErrorAction SilentlyContinue; $(GO) build $(GOFLAGS) -ldflags '$(LDFLAGS)' -o $(BUILD_DIR)/$(APP_NAME)-linux-mips $(CMD_PATH)
else
build-arm-mips:
	$(info >>> MIPS (big-endian)...)
	GOOS=linux GOARCH=mips GOMIPS=softfloat $(GO) build $(GOFLAGS) -ldflags "$(LDFLAGS)" -o $(BUILD_DIR)/$(APP_NAME)-linux-mips $(CMD_PATH)
endif

ifeq ($(OS),Windows_NT)
build-arm-mipsle:
	$(info >>> MIPS (little-endian)...)
	$$env:GOOS='linux'; $$env:GOARCH='mipsle'; $$env:GOMIPS='softfloat'; Remove-Item Env:GOARM -ErrorAction SilentlyContinue; $(GO) build $(GOFLAGS) -ldflags '$(LDFLAGS)' -o $(BUILD_DIR)/$(APP_NAME)-linux-mipsle $(CMD_PATH)
else
build-arm-mipsle:
	$(info >>> MIPS (little-endian)...)
	GOOS=linux GOARCH=mipsle GOMIPS=softfloat $(GO) build $(GOFLAGS) -ldflags "$(LDFLAGS)" -o $(BUILD_DIR)/$(APP_NAME)-linux-mipsle $(CMD_PATH)
endif

ifeq ($(OS),Windows_NT)
build-arm-riscv64:
	$(info >>> RISC-V 64...)
	$$env:GOOS='linux'; $$env:GOARCH='riscv64'; Remove-Item Env:GOARM,Env:GOMIPS -ErrorAction SilentlyContinue; $(GO) build $(GOFLAGS) -ldflags '$(LDFLAGS)' -o $(BUILD_DIR)/$(APP_NAME)-linux-riscv64 $(CMD_PATH)
else
build-arm-riscv64:
	$(info >>> RISC-V 64...)
	GOOS=linux GOARCH=riscv64 $(GO) build $(GOFLAGS) -ldflags "$(LDFLAGS)" -o $(BUILD_DIR)/$(APP_NAME)-linux-riscv64 $(CMD_PATH)
endif


# ============================================================================
#  FreeBSD
# ============================================================================

build-freebsd: build-freebsd-amd64 build-freebsd-arm64

ifeq ($(OS),Windows_NT)
build-freebsd-amd64:
	$(info >>> FreeBSD amd64...)
	$$env:GOOS='freebsd'; $$env:GOARCH='amd64'; Remove-Item Env:GOARM,Env:GOMIPS -ErrorAction SilentlyContinue; $(GO) build $(GOFLAGS) -ldflags '$(LDFLAGS)' -o $(BUILD_DIR)/$(APP_NAME)-freebsd-amd64 $(CMD_PATH)
else
build-freebsd-amd64:
	$(info >>> FreeBSD amd64...)
	GOOS=freebsd GOARCH=amd64 $(GO) build $(GOFLAGS) -ldflags "$(LDFLAGS)" -o $(BUILD_DIR)/$(APP_NAME)-freebsd-amd64 $(CMD_PATH)
endif

ifeq ($(OS),Windows_NT)
build-freebsd-arm64:
	$(info >>> FreeBSD arm64...)
	$$env:GOOS='freebsd'; $$env:GOARCH='arm64'; Remove-Item Env:GOARM,Env:GOMIPS -ErrorAction SilentlyContinue; $(GO) build $(GOFLAGS) -ldflags '$(LDFLAGS)' -o $(BUILD_DIR)/$(APP_NAME)-freebsd-arm64 $(CMD_PATH)
else
build-freebsd-arm64:
	$(info >>> FreeBSD arm64...)
	GOOS=freebsd GOARCH=arm64 $(GO) build $(GOFLAGS) -ldflags "$(LDFLAGS)" -o $(BUILD_DIR)/$(APP_NAME)-freebsd-arm64 $(CMD_PATH)
endif


# ============================================================================
#  OpenBSD
# ============================================================================

build-openbsd: build-openbsd-amd64

ifeq ($(OS),Windows_NT)
build-openbsd-amd64:
	$(info >>> OpenBSD amd64...)
	$$env:GOOS='openbsd'; $$env:GOARCH='amd64'; Remove-Item Env:GOARM,Env:GOMIPS -ErrorAction SilentlyContinue; $(GO) build $(GOFLAGS) -ldflags '$(LDFLAGS)' -o $(BUILD_DIR)/$(APP_NAME)-openbsd-amd64 $(CMD_PATH)
else
build-openbsd-amd64:
	$(info >>> OpenBSD amd64...)
	GOOS=openbsd GOARCH=amd64 $(GO) build $(GOFLAGS) -ldflags "$(LDFLAGS)" -o $(BUILD_DIR)/$(APP_NAME)-openbsd-amd64 $(CMD_PATH)
endif


# ============================================================================
#  NetBSD
# ============================================================================

build-netbsd: build-netbsd-amd64

ifeq ($(OS),Windows_NT)
build-netbsd-amd64:
	$(info >>> NetBSD amd64...)
	$$env:GOOS='netbsd'; $$env:GOARCH='amd64'; Remove-Item Env:GOARM,Env:GOMIPS -ErrorAction SilentlyContinue; $(GO) build $(GOFLAGS) -ldflags '$(LDFLAGS)' -o $(BUILD_DIR)/$(APP_NAME)-netbsd-amd64 $(CMD_PATH)
else
build-netbsd-amd64:
	$(info >>> NetBSD amd64...)
	GOOS=netbsd GOARCH=amd64 $(GO) build $(GOFLAGS) -ldflags "$(LDFLAGS)" -o $(BUILD_DIR)/$(APP_NAME)-netbsd-amd64 $(CMD_PATH)
endif


# ============================================================================
#  Релиз
# ============================================================================

.PHONY: release checksum

## Копирование бинарников в build/release/ (внутренняя цель)
ifeq ($(OS),Windows_NT)
release-prepare: build-all
	$(info >>> Копирование бинарников в release/...)
	New-Item -ItemType Directory -Force '$(BUILD_DIR)\release' | Out-Null
	Get-ChildItem '$(BUILD_DIR)' -File | Where-Object { $$_.Name -ne '.env' } | Copy-Item -Destination '$(BUILD_DIR)\release\'
	$(info >>> Готово: $(BUILD_DIR)/release/)
else
release-prepare: build-all
	$(info >>> Копирование бинарников в release/...)
	@mkdir -p $(BUILD_DIR)/release
	@find $(BUILD_DIR) -maxdepth 1 -type f -not -name '.env' -exec cp {} $(BUILD_DIR)/release/ \;
	$(info >>> Готово: $(BUILD_DIR)/release/)
endif

## Генерация контрольных сумм SHA256
ifeq ($(OS),Windows_NT)
checksum: release-prepare
	$(info >>> Генерация SHA256...)
	Remove-Item -ErrorAction SilentlyContinue '$(BUILD_DIR)\release\checksums-sha256.txt'; Get-ChildItem '$(BUILD_DIR)\release\' -File | Get-FileHash -Algorithm SHA256 | ForEach-Object { "$$($$_.Hash)  $$(Split-Path $$_.Path -Leaf)" } | Out-File -Encoding UTF8 '$(BUILD_DIR)\release\checksums-sha256.txt'
	$(info >>> Готово: $(BUILD_DIR)/release/checksums-sha256.txt)
else
checksum: release-prepare
	$(info >>> Генерация SHA256...)
	@cd $(BUILD_DIR)/release && sha256sum $(APP_NAME)-* > checksums-sha256.txt
	$(info >>> Готово: $(BUILD_DIR)/release/checksums-sha256.txt)
endif

# ============================================================================
#  CI/CD — Управление релизами через Gitea
#
#  Пайплайн описан в .gitea/workflows/release.yml
#  Запускать ТОЛЬКО через команды make ниже — не вручную.
# ============================================================================

## Полный релиз: сборка + архивы + тег + создание Gitea Release + загрузка файлов
## Использование: make release VERSION=2.1.0 GIT_TOKEN=<токен>
## Если GIT_TOKEN не указан — соберёт локально и создаст тег, но не загрузит в Gitea
ifeq ($(OS),Windows_NT)
release:
	@powershell.exe -NoProfile -ExecutionPolicy Bypass -File scripts\release.ps1 -Version '$(VERSION)' -Token '$(or $(GIT_TOKEN),$(GITEA_TOKEN))' -AppName '$(APP_NAME)' -BuildDir '$(BUILD_DIR)' -GiteaUrl '$(GITEA_URL)' -GiteaRepo '$(GITEA_REPO)' -GoVersion '$(GO_VERSION)'
else
release:
	@v="$(VERSION)"; tag="v$$v"; token="$(GIT_TOKEN)"; [ -z "$$token" ] && token="$(GITEA_TOKEN)"; \
	if [ "$$v" = "dev" ] || [ -z "$$v" ]; then echo "!!! VERSION не указана. Использование: make release VERSION=X.Y.Z"; exit 1; fi; \
	if [ -n "$$(git status --porcelain)" ]; then echo "!!! Есть незакоммиченные изменения."; git status --short; exit 1; fi; \
	echo ""; \
	echo "══════════════════════════════════════════════"; \
	echo "  Создание релиза $$tag"; \
	echo "══════════════════════════════════════════════"; \
	echo ""; \
	echo ">>> [1/6] Кросс-компиляция..."; \
	make build-all VERSION=$$v; \
	echo ""; \
	echo ">>> [2/6] Создание архивов..."; \
	mkdir -p $(BUILD_DIR)/archives; \
	cd $(BUILD_DIR) && for f in *; do \
		[ -f "$$f" ] || continue; \
		case "$$f" in \
			*.exe) arcname="$${f%.exe}.zip"; echo "  $$f → $$arcname"; zip "archives/$$arcname" "$$f" ;; \
			$(APP_NAME)-*) arcname="$$f.tar.gz"; echo "  $$f → $$arcname"; tar -czf "archives/$$arcname" "$$f" ;; \
		esac; \
	done; cd ..; \
	echo ""; \
	echo ">>> [3/6] SHA256..."; \
	cd $(BUILD_DIR)/archives && sha256sum * > checksums-sha256.txt && cd ../..; \
	echo ""; \
	echo ">>> [4/6] Создание тега $$tag..."; \
	if git tag -l "$$tag" | grep -q .; then echo "  Тег $$tag уже существует, пропускаю"; \
	else git tag -a "$$tag" -m "Release $$tag"; fi; \
	git push origin "$$tag" 2>/dev/null || true; \
	git push origin master 2>/dev/null || true; \
	echo ""; \
	if [ -z "$$token" ]; then \
		echo "══════════════════════════════════════════════"; \
		echo "  Локальная сборка завершена."; \
		echo "  Для загрузки в Gitea укажите GIT_TOKEN:"; \
		echo "    make release VERSION=$$v GIT_TOKEN=<токен>"; \
		echo "  Архивы: $(BUILD_DIR)/archives/"; \
		echo "══════════════════════════════════════════════"; \
		exit 0; \
	fi; \
	echo ">>> [5/6] Создание релиза в Gitea..."; \
	GITEA_URL="$(GITEA_URL)"; REPO="$(GITEA_REPO)"; \
	COMMIT=$$(git rev-parse HEAD); \
	DATE=$$(date -u '+%d.%m.%Y %H:%M UTC'); \
	PREV_TAG=$$(git describe --tags --abbrev=0 "$$tag^" 2>/dev/null || echo ""); \
	if [ -n "$$PREV_TAG" ]; then RAW_LOG=$$(git log --pretty=format:"%s" "$$PREV_TAG..$$tag" --no-merges 2>/dev/null); \
	else RAW_LOG=$$(git log --pretty=format:"%s" --no-merges | head -50); fi; \
	FEATS=""; FIXES=""; REFAC=""; OTHER=""; \
	echo "$$RAW_LOG" | while IFS= read -r line; do \
		[ -z "$$line" ] && continue; \
		low=$$(echo "$$line" | tr '[:upper:]' '[:lower:]'); \
		case "$$low" in \
			функция:*|feat:*|feature:*|добавлен*|реализован*|новое:*) FEATS="$$FEATS\n- $$line" ;; \
			исправлен*|fix:*|bugfix:*) FIXES="$$FIXES\n- $$line" ;; \
			рефакторинг:*|refactor:*|оптимизац*|улучшен*) REFAC="$$REFAC\n- $$line" ;; \
			*) OTHER="$$OTHER\n- $$line" ;; \
		esac; \
	done; \
	BODY="## BookFlow Metadata Engine $$tag\n\n"; \
	[ -f RELEASE_NOTES.md ] && BODY="$$BODY$$(cat RELEASE_NOTES.md)\n\n"; \
	BODY="$$BODY---\n\n### Информация о сборке\n\n| Параметр | Значение |\n|---|---|\n| Коммит | \`$$COMMIT\` |\n| Дата | $$DATE |\n"; \
	BODY_JSON=$$(printf '%s' "$$BODY" | python3 -c 'import sys,json; print(json.dumps(sys.stdin.read()))'); \
	RELEASE_JSON=$$(curl -sf -X POST \
		-H "Authorization: token $$token" \
		-H "Content-Type: application/json" \
		"$$GITEA_URL/api/v1/repos/$$REPO/releases" \
		-d "{\"tag_name\":\"$$tag\",\"target_commitish\":\"$$COMMIT\",\"name\":\"$(APP_NAME) $$tag\",\"body\":$$BODY_JSON,\"draft\":false,\"prerelease\":false}"); \
	RELEASE_ID=$$(echo "$$RELEASE_JSON" | python3 -c "import sys,json;print(json.load(sys.stdin).get('id',''))" 2>/dev/null); \
	if [ -z "$$RELEASE_ID" ] || [ "$$RELEASE_ID" = "None" ]; then echo "ОШИБКА: не удалось создать релиз!"; echo "$$RELEASE_JSON"; exit 1; fi; \
	echo "  Релиз создан: ID=$$RELEASE_ID"; \
	echo ""; \
	echo ">>> [6/6] Загрузка файлов..."; \
	OK=0; FAIL=0; \
	for FILE in $(BUILD_DIR)/archives/*; do \
		[ -f "$$FILE" ] || continue; \
		FNAME=$$(basename "$$FILE"); FSIZE=$$(du -sh "$$FILE" | cut -f1); \
		printf "  %-55s [%5s]  " "$$FNAME" "$$FSIZE"; \
		HTTP=$$(curl -s -o /dev/null -w "%{http_code}" -X POST \
			-H "Authorization: token $$token" \
			-H "Content-Type: application/octet-stream" \
			--data-binary @"$$FILE" \
			"$$GITEA_URL/api/v1/repos/$$REPO/releases/$$RELEASE_ID/assets?name=$$FNAME"); \
		if [ "$$HTTP" -ge 200 ] && [ "$$HTTP" -lt 300 ]; then echo "OK"; OK=$$((OK+1)); \
		else echo "ОШИБКА (HTTP $$HTTP)"; FAIL=$$((FAIL+1)); fi; \
	done; \
	echo ""; \
	echo "══════════════════════════════════════════════"; \
	echo "  Загружено: $$OK  |  Ошибок: $$FAIL"; \
	echo "  Релиз: $$GITEA_URL/$$REPO/releases/tag/$$tag"; \
	echo "══════════════════════════════════════════════"; \
	[ "$$FAIL" -gt 0 ] && exit 1; true
endif

## Проверить git-статус перед созданием тега
ci-check:
	$(info >>> Состояние рабочего дерева:)
	git status --short
	$(info >>> Последние коммиты:)
	git log --oneline -5
	$(info >>> Убедитесь что все изменения закоммичены перед релизом.)

## Создать git-тег v$(VERSION) и запушить в origin — запускает CI/CD автоматически
## Использование: make release-tag VERSION=2.1.0
release-tag:
ifeq ($(VERSION),2.0.0)
	$(info !!! Версия не изменена ($(VERSION)). Укажите: make release-tag VERSION=X.Y.Z)
endif
	$(info >>> Создание тега v$(VERSION)...)
	git tag -a "v$(VERSION)" -m "Release v$(VERSION)"
	git push origin "v$(VERSION)"
	$(info >>> Тег v$(VERSION) запушен. CI/CD pipeline запущен автоматически в Gitea.)
	$(info >>> Статус: $(GITEA_URL)/$(GITEA_REPO)/actions)

## Удалить ошибочный тег (локально и в origin)
## Использование: make release-tag-delete VERSION=2.1.0
release-tag-delete:
	$(info >>> Удаление тега v$(VERSION)...)
	-git tag -d "v$(VERSION)"
	-git push origin --delete "v$(VERSION)"
	$(info >>> Тег v$(VERSION) удалён.)

## Запустить CI/CD workflow вручную через Gitea API (без создания тега)
## Использование: make ci-release VERSION=2.1.0 GIT_TOKEN=<токен>
ifeq ($(OS),Windows_NT)
ci-release:
	$(if $(or $(GIT_TOKEN),$(GITEA_TOKEN)),,$(error GIT_TOKEN (или GITEA_TOKEN) не задан. Используйте: make ci-release GIT_TOKEN=<токен>))
	@Write-Host ">>> Запуск CI/CD workflow для версии $(VERSION)..."; Invoke-RestMethod -Method Post -Uri '$(GITEA_URL)/api/v1/repos/$(GITEA_REPO)/actions/workflows/release.yml/dispatches' -Headers @{ Authorization = 'token $(if $(GIT_TOKEN),$(GIT_TOKEN),$(GITEA_TOKEN))'; 'Content-Type' = 'application/json' } -Body '{"ref": "master", "inputs": {"version": "$(VERSION)"}}'; Write-Host ">>> Workflow запущен. Статус: $(GITEA_URL)/$(GITEA_REPO)/actions"
else
ci-release:
	$(if $(or $(GIT_TOKEN),$(GITEA_TOKEN)),,$(error GIT_TOKEN (или GITEA_TOKEN) не задан. Используйте: make ci-release GIT_TOKEN=<токен>))
	@echo ">>> Запуск CI/CD workflow для версии $(VERSION)..."
	@curl -sf -X POST \
		-H "Authorization: token $(if $(GIT_TOKEN),$(GIT_TOKEN),$(GITEA_TOKEN))" \
		-H "Content-Type: application/json" \
		"$(GITEA_URL)/api/v1/repos/$(GITEA_REPO)/actions/workflows/release.yml/dispatches" \
		-d '{"ref": "master", "inputs": {"version": "$(VERSION)"}}' \
		&& echo "Workflow запущен. Статус: $(GITEA_URL)/$(GITEA_REPO)/actions"
endif

## Полная локальная сборка + архивы + SHA256 (без загрузки в Gitea)
## Результат в build/release/
release-local: checksum
	$(info >>> Локальный релиз готов в $(BUILD_DIR)/release/)

# ============================================================================
#  Wiki — синхронизация локальной папки wiki/ в Gitea Wiki
# ============================================================================

## Синхронизировать папку wiki/ в удалённый wiki-репозиторий (<origin>.wiki.git)
ifeq ($(OS),Windows_NT)
wiki-update:
	$(info >>> Синхронизация wiki в Gitea...)
	@$$ErrorActionPreference = "Stop"; if (-Not (Test-Path "wiki")) { throw "wiki/ folder not found." }; $$origin = git remote get-url origin; if (-not $$origin) { throw "origin remote not found." }; if ($$origin -match "\.git$$") { $$wikiUrl = $$origin -replace "\.git$$", ".wiki.git" } else { $$wikiUrl = "$$origin.wiki.git" }; $$tmp = "$(BUILD_DIR)\\.wiki-sync"; Remove-Item -Recurse -Force $$tmp -ErrorAction SilentlyContinue; New-Item -ItemType Directory -Force "$(BUILD_DIR)" | Out-Null; git clone --depth 1 $$wikiUrl $$tmp; robocopy wiki $$tmp /MIR /XD .git | Out-Null; if ($$LASTEXITCODE -gt 7) { throw "robocopy failed while syncing wiki." }; Push-Location $$tmp; git add -A; git diff --cached --quiet; if ($$LASTEXITCODE -eq 0) { Write-Host "No wiki changes."; Pop-Location; exit 0 }; git config user.name "wiki-sync-bot"; git config user.email "wiki-sync@local"; git commit -m "docs(wiki): sync from main repo"; git push origin HEAD; Pop-Location; Write-Host "Wiki synced successfully."
else
wiki-update:
	$(info >>> Синхронизация wiki в Gitea...)
	@test -d wiki || (echo "Папка wiki/ не найдена." && exit 1)
	@ORIGIN=$$(git remote get-url origin); \
	if [ -z "$$ORIGIN" ]; then echo "Не найден remote origin."; exit 1; fi; \
	if echo "$$ORIGIN" | grep -q '\.git$$'; then WIKI_URL=$$(echo "$$ORIGIN" | sed 's/\.git$$/.wiki.git/'); else WIKI_URL="$$ORIGIN.wiki.git"; fi; \
	TMP_DIR="$(BUILD_DIR)/.wiki-sync"; \
	rm -rf "$$TMP_DIR"; mkdir -p "$(BUILD_DIR)"; \
	git clone --depth 1 "$$WIKI_URL" "$$TMP_DIR"; \
	rsync -a --delete --exclude '.git/' wiki/ "$$TMP_DIR"/; \
	cd "$$TMP_DIR"; \
	git add -A; \
	if git diff --cached --quiet; then echo ">>> Изменений в wiki нет."; exit 0; fi; \
	git config user.name "wiki-sync-bot"; \
	git config user.email "wiki-sync@local"; \
	git commit -m "docs(wiki): sync from main repo"; \
	git push origin HEAD; \
	echo ">>> Wiki успешно обновлена."
endif

# ============================================================================
#  Справка
# ============================================================================

## Показать справку
help:
	$(info )
	$(info   BookFlow Metadata Engine v$(VERSION) — Makefile)
	$(info   ─────────────────────────────────────────)
	$(info )
	$(info   Основные:)
	$(info     make build                Сборка для текущей платформы)
	$(info     make build-windows-current Сборка bookflow-metadata.exe)
	$(info     make run                  Запуск без сборки (workers=8, timeout=60m))
	$(info     make run-custom ARGS="…"  Запуск с параметрами)
	$(info     make clean                Очистка артефактов сборки)
	$(info     make clean-results        Очистка директории результатов)
	$(info     make clean-all            Полная очистка)
	$(info )
	$(info   Тестирование:)
	$(info     make test                 Unit-тесты)
	$(info     make test-cover           Тесты с покрытием кода)
	$(info )
	$(info   Качество кода:)
	$(info     make fmt                  Форматирование (go fmt))
	$(info     make vet                  Статический анализ (go vet))
	$(info     make lint                 Линтер (golangci-lint))
	$(info     make tidy                 Обновление go.mod/go.sum)
	$(info )
	$(info   Кросс-компиляция:)
	$(info     make build-all            Все платформы (16 бинарников))
	$(info     make build-linux          Linux: amd64, 386, arm64, armv7)
	$(info     make build-darwin         macOS: amd64 (Intel), arm64 (Apple Silicon))
	$(info     make build-windows        Windows: amd64, 386, arm64)
	$(info     make build-arm            Embedded: MIPS, MIPSle, RISC-V 64)
	$(info     make build-freebsd        FreeBSD: amd64, arm64)
	$(info     make build-openbsd        OpenBSD: amd64)
	$(info     make build-netbsd         NetBSD: amd64)
	$(info )
	$(info   Релиз:)
	$(info     make release VERSION=X.Y.Z GIT_TOKEN=xxx  Полный релиз: сборка + тег + публикация в Gitea)
	$(info     make release VERSION=X.Y.Z               Только локальная сборка без загрузки)
	$(info     make release-tag-delete VERSION=X.Y.Z    Удалить ошибочный тег)
	$(info     make ci-check                             Проверить git-статус перед релизом)
	$(info )
	$(info   Дополнительно:)
	$(info     make release-local        Все платформы + архивы + SHA256 → build/release/)
	$(info     make checksum             Сборка + SHA256 контрольные суммы)
	$(info )
	$(info   Wiki:)
	$(info     make wiki-update               Синхронизировать локальную папку wiki/ в Gitea Wiki)
	$(info )

.DEFAULT_GOAL := help
