package app

import (
	"context"
	"errors"
	"log"
	"net/http"
	"os"

	"git.az-it.net/az/morz-infoboard/server/backend/internal/config"
	"git.az-it.net/az/morz-infoboard/server/backend/internal/db"
	"git.az-it.net/az/morz-infoboard/server/backend/internal/httpapi"
	"git.az-it.net/az/morz-infoboard/server/backend/internal/store"
)

type App struct {
	Config config.Config
	server *http.Server
}

func New() (*App, error) {
	cfg := config.Load()
	logger := log.New(os.Stdout, "backend ", log.LstdFlags|log.LUTC)

	// Ensure upload directory exists.
	if err := os.MkdirAll(cfg.UploadDir, 0755); err != nil {
		return nil, err
	}

	// Connect to database and run migrations.
	pool, err := db.Connect(context.Background(), cfg.DatabaseURL, logger)
	if err != nil {
		return nil, err
	}

	// Status store (existing in-memory/file store).
	statusStore, err := httpapi.NewStoreFromConfig(cfg.StatusStorePath)
	if err != nil {
		pool.Close()
		return nil, err
	}

	// Domain stores.
	tenants := store.NewTenantStore(pool.Pool)
	screens := store.NewScreenStore(pool.Pool)
	media := store.NewMediaStore(pool.Pool)
	playlists := store.NewPlaylistStore(pool.Pool)

	handler := httpapi.NewRouter(httpapi.RouterDeps{
		StatusStore:   statusStore,
		TenantStore:   tenants,
		ScreenStore:   screens,
		MediaStore:    media,
		PlaylistStore: playlists,
		UploadDir:     cfg.UploadDir,
		Logger:        logger,
	})

	return &App{
		Config: cfg,
		server: &http.Server{
			Addr:    cfg.HTTPAddress,
			Handler: handler,
		},
	}, nil
}

func (a *App) Run() error {
	err := a.server.ListenAndServe()
	if errors.Is(err, http.ErrServerClosed) {
		return nil
	}
	return err
}
