// Package store defines database functions
package store

import (
	_ "embed"
	"log/slog"
	"strings"
	"time"

	"quantex.com.ar/multidb"
	"quantex.com/qfixdpl/src/app"
	"quantex.com/qfixdpl/src/client/store/external"
	"quantex.com/qfixdpl/src/common/tracerr"
)

//go:embed db.sql
var schemaSQL string

const dbPingSeconds = 30

type Store struct {
	db  *multidb.MultiDB
	ext *external.Manager
}

type Config struct {
	MultiDB  multidb.Config
	External external.Config
}

// New NewStore creates Store object
func New(config Config) (*Store, error) {
	database, err := multidb.New("postgres", config.MultiDB)
	if err != nil {
		return nil, tracerr.Errorf("error trying to create multidb: %w", err)
	}

	database.Start()

	if err = database.Ping(); err != nil {
		return nil, tracerr.Errorf("error ping to database: %w", err)
	}

	ext := external.NewManager(nil, config.External)

	s := &Store{
		db:  database,
		ext: ext,
	}

	go s.db.PeriodicDBPing(time.Second * dbPingSeconds)

	if err := s.ensureTables(); err != nil {
		return nil, tracerr.Errorf("error ensuring tables: %w", err)
	}

	return s, nil
}

func (p *Store) ensureTables() error {
	statements := strings.Split(schemaSQL, ";")
	for _, stmt := range statements {
		stmt = strings.TrimSpace(stmt)
		if stmt == "" {
			continue
		}

		if _, err := p.db.Exec(stmt); err != nil {
			return tracerr.Errorf("error executing schema statement: %w", err)
		}
	}

	slog.Info("database tables ensured")

	return nil
}

func (p *Store) CloseDB() {
	p.db.Close()
	slog.Info("closing database connection.")
}

func (p *Store) UserByEmail(email string) (out *app.User, err error) {
	var user app.User
	if err := p.ext.UserByEmail(email, &user); err != nil {
		return nil, tracerr.Errorf("error fetching user by email from external service: %w", err)
	}

	return &user, nil
}

func (p *Store) ValidateSession(sessionToken string) (bool, error) {
	ok, err := p.ext.ValidateSession(sessionToken)
	if err != nil {
		return false, tracerr.Errorf("error validating session: %w", err)
	}

	return ok, nil
}
