// Package pocketbase — хранилище задач и файлов поверх встроенной PocketBase.
//
// Приложение поднимается библиотекой, а не её набором команд: разбор флагов и
// мягкая остановка остаются нашими, а ключ `-c config.toml` — объявленный
// контракт запуска.
package pocketbase

import (
	"fmt"

	pb "github.com/pocketbase/pocketbase"
	"github.com/pocketbase/pocketbase/core"

	// Шаги схемы регистрируются загрузкой своего пакета, а накатывает их
	// `RunAllMigrations` ниже. Импорт здесь пустой и явный, хотя соседние файлы
	// пакета и так берут оттуда имена коллекций: день, когда имена перестанут
	// читаться отсюда, унёс бы вместе с последней ссылкой и регистрацию — список
	// шагов остался бы пустым, `RunAllMigrations` вернул бы `nil`, и приложение
	// поднялось бы здоровым, но без коллекций. Отказ вылез бы не на старте, а на
	// первом приёме записи.
	_ "git.vakhrushev.me/av/transcriber/internal/adapter/repo/pocketbase/migrations"
)

// New создаёт приложение хранилища на заданном каталоге данных и приводит его в
// рабочее состояние: открывает базу, читает настройки и накатывает непринятые
// шаги схемы.
//
// Схема накатывается **здесь**, а не оставляется серверу, хотя тот и гоняет
// непринятые шаги сам. Причина в порядке: воркеры стартуют раньше сервера, и на
// чистом каталоге их первые опросы приходились бы на несуществующую таблицу —
// отказ в журнале и в счётчике на каждую секунду до конца накатки.
func New(dataDir string) (*pb.PocketBase, error) {
	app := pb.NewWithConfig(pb.Config{
		DefaultDataDir:  dataDir,
		HideStartBanner: true,
	})

	if err := app.Bootstrap(); err != nil {
		return nil, fmt.Errorf("failed to bootstrap storage: %w", err)
	}

	if err := app.RunAllMigrations(); err != nil {
		return nil, fmt.Errorf("failed to apply storage schema: %w", err)
	}

	// Страж владельца вешается здесь, а не вызывающим: он защищает архив от
	// удаления учётной записи, и сборка, забывшая его позвать, теряет защиту
	// молча. Так это уже и было — окружение проверок его не ставило, и всё
	// разграничение проверялось на приложении, где архив сносится одним
	// запросом.
	GuardOwnerDeletion(app)

	return app, nil
}

// MustFindCollection достаёт коллекцию по имени. Отсутствие коллекции здесь —
// не отказ окружения, а несделанный шаг схемы: сервис до этой точки не доходит,
// потому что Serve накатывает схему прежде, чем поднять сервер.
func findCollection(app core.App, name string) (*core.Collection, error) {
	collection, err := app.FindCollectionByNameOrId(name)
	if err != nil {
		return nil, fmt.Errorf("failed to find collection %s: %w", name, err)
	}
	return collection, nil
}
