# Подъём стенда и рутина. Цели, которых ещё нет, честно падают
# и называют карточку, которая их закрывает, — README не должен врать.

UV ?= uv

# `make test` и `make demo` не запускать одновременно: они просят у uv разные
# группы зависимостей, и uv пересобирает одно и то же окружение, а второй запуск
# молча ждёт блокировку. Один раз поставить оба набора:
#   cd backend && uv sync --extra dev --extra voice
COMPOSE ?= docker compose
DEMO_PORT ?= 8112

.DEFAULT_GOAL := help

help:                     ## Список целей
	@grep -hE '^[a-z-]+:.*##' $(MAKEFILE_LIST) | sed 's/:.*##/\t/' | expand -t22

dev: ## Поднять стенд: postgres + backend --reload + frontend
	$(COMPOSE) up --build

offline: ## Поднять карточки/ДДС из заранее собранных локальных образов, без скачивания
	$(COMPOSE) up --pull never --no-build

tls: ## Поднять полный стенд по HTTPS/WSS с локальным сертификатом
	$(COMPOSE) -f docker-compose.yml -f docker-compose.tls.yml up --build

offline-tls: ## Поднять HTTPS/WSS из уже собранных образов без сети
	$(COMPOSE) -f docker-compose.yml -f docker-compose.tls.yml up --pull never --no-build

production: ## Защищённый запуск из исходников: уникальный DB-пароль обязателен
	bash scripts/validate_production_env.sh
	$(COMPOSE) -f docker-compose.yml -f docker-compose.production.yml -f docker-compose.tls.yml up --build

offline-production: ## Защищённый запуск готовых образов без pull/build; требуется уникальный DB-пароль
	bash scripts/validate_production_env.sh
	$(COMPOSE) -f docker-compose.yml -f docker-compose.production.yml -f docker-compose.tls.yml up --pull never --no-build

production-config-check: ## Проверить, что production Compose требует и передаёт заданный DB-пароль
	bash scripts/check_production_compose.sh

production-postgres-check: ## Проверить межконтейнерную PostgreSQL-аутентификацию на временной БД
	bash scripts/test_production_postgres.sh

sip: ## Собрать и поднять локальный Asterisk SIP/VoIP
	$(COMPOSE) -f docker-compose.yml -f docker-compose.sip.yml up --build -d sip

offline-sip: ## Поднять SIP из уже собранного образа без сети
	$(COMPOSE) -f docker-compose.yml -f docker-compose.sip.yml up --pull never --no-build -d sip

sip-credentials: ## Показать локальные пароли софтфонов 6001–6003 и WebRTC 6101–6102
	$(COMPOSE) -f docker-compose.yml -f docker-compose.sip.yml exec -T sip cat /var/lib/lct-sip/credentials.env

sip-test: ## Проверить регистрацию, звонок, RTP и задержку (args="--rtp-host-offset 1000")
	python3 scripts/smoke_sip.py --port $(or $(SIP_PORT),5060) $(args)

webrtc-test: ## Проверить два браузерных SIP-клиента, аудио и запись Asterisk
	python3 scripts/smoke_webrtc_browser.py \
		--frontend-url https://127.0.0.1:$(or $(TLS_PORT),5443) \
		--backend-url http://127.0.0.1:$(or $(BACKEND_PORT),8000) \
		--database-url postgresql+asyncpg://lct:lct@127.0.0.1:$(or $(POSTGRES_PORT),5432)/lct $(args)

webrtc-test-isolated: ## Полный двухбраузерный WebRTC smoke на отдельной БД, портах и volume
	bash scripts/test_webrtc_isolated.sh

down: ## Погасить стенд
	$(COMPOSE) down

back: ## Бэкенд нативно, без голоса по умолчанию (порт 8000: сначала docker compose stop backend)
	cd backend && $(UV) run --extra voice uvicorn app.main:app --reload --port 8000 --workers 1

front: ## Только фронтенд, локально
	npm --prefix frontend install && npm --prefix frontend run dev

types: ## domain/events.py → frontend/src/shared/types/generated.ts
	cd backend && $(UV) run --no-project --with 'pydantic>=2.7' python scripts/export_types.py

test: ## Тесты бэкенда (голосовой контур пропускается)
	cd backend && $(UV) run --extra dev pytest -q

test-db: ## Полный backend-прогон на новой временной PostgreSQL, без касания dev-базы
	bash scripts/test_isolated_db.sh $(args)

test-voice: ## Тест голосового контура на настоящих моделях: задержка и перебивание
	cd backend && $(UV) run --extra dev --extra voice pytest tests/test_voice_pipeline.py -q -s

typecheck: ## Проверить фронтенд компилятором
	npm --prefix frontend run typecheck

models: ## Скачать эмбеддинги и Silero VAD; Silero TTS — вручную
	cd backend && $(UV) run python scripts/models.py

local-models: ## Скачать и проверить Qwen3 1.7B, Vikhr 1B, Whisper small (нужна сеть один раз)
	cd backend && $(UV) run --offline --no-sync python scripts/download_local_models.py

local-llm: ## Запустить Qwen3 на localhost:18080 (mode=both для Qwen3 и Vikhr)
	cd backend && python3 scripts/local_llms.py --mode $(or $(mode),dialogue)

local-stt: ## Запустить локальный whisper.cpp server на localhost:18082
	cd backend && python3 scripts/local_stt.py

backup: ## Резервная копия базы в backend/backups/ (для cron: раз в сутки)
	cd backend && $(UV) run python scripts/backup.py

users: ## Завести учётные записи ролей и напечатать пароли: make users force=1
	cd backend && $(UV) run python scripts/users.py

users-docker: ## Завести учётные записи внутри локального контейнера (после make offline)
	$(COMPOSE) exec backend python scripts/users.py

seed: ## Залить сценарии из /scenarios в БД
	cd backend && $(UV) run python scripts/seed.py

lesson: ## Запустить занятие и напечатать ссылки: make lesson s=<сценарий> m=<режим>
	cd backend && $(UV) run --no-project --with websockets python scripts/start_lesson.py "$(s)" "$(m)"

test-llm-local: ## Живые проверки локального Qwen по backend/.env.test (без сети)
	test -f backend/.env.test || (echo "Создайте backend/.env.test из backend/.env.test.example"; exit 2)
	cd backend && $(UV) run --offline --extra dev pytest tests/test_llm.py -m llm -q -s

test-llm: test-llm-local ## Совместимое имя цели локальной проверки LLM

llm-check: ## Один запрос к активной локальной модели из backend/.env
	cd backend && $(UV) run python scripts/llm_check.py

latency: ## Замер задержки голосового контура по этапам — запускать на демо-машине
	cd backend && $(UV) run --extra voice python scripts/latency.py

migrate: ## Накатить миграции
	cd backend && $(UV) run alembic upgrade head

revision: ## Создать миграцию: make revision m="что изменилось"
	cd backend && $(UV) run alembic revision --autogenerate -m "$(m)"

repl: ## Текстовый диалог со звонящим без голоса: make repl s=<сценарий>
	cd backend && $(UV) run python scripts/repl.py "$(s)"

pregen: ## Офлайн-таблицы реплик: make pregen [s=<сценарий>] [t=<билет>] [force=1]
	cd backend && s="$(s)" t="$(t)" force="$(force)" $(UV) run python scripts/pregenerate.py

demo: ## Поднять основной стенд ДДС: база, готовые карточки, бэкенд и фронт
	./scripts/demo.sh

demo-lite: ## Локальная демонстрация карточки/ДДС без Docker, БД, голоса и внешней сети
	cd backend && UV_CACHE_DIR=/tmp/lct-uv-demo-cache OFFLINE=true VOICE_ENABLED=false DEV_AUTH_BYPASS=true DEMO_NO_DB=true $(UV) run --offline --no-sync uvicorn app.main:app --host 127.0.0.1 --port $(DEMO_PORT) --workers 1

.PHONY: help dev offline tls offline-tls production offline-production production-config-check production-postgres-check sip offline-sip sip-credentials sip-test webrtc-test webrtc-test-isolated down back front types users users-docker backup test test-db test-voice typecheck test-llm test-llm-local lesson llm-check latency migrate revision models local-models local-llm local-stt seed repl pregen demo demo-lite
