package metastore

import (
	"errors"
	"fmt"
	"strings"
	"time"

	"github.com/dgraph-io/badger/v4"

	"warpbox/lib/helpers"
)

func (store *Store) CreateSession(userID string, ttl time.Duration) (Session, error) {
	userID = strings.TrimSpace(userID)
	if userID == "" {
		return Session{}, fmt.Errorf("%w: user id cannot be empty", ErrInvalid)
	}
	if ttl <= 0 {
		return Session{}, fmt.Errorf("%w: session ttl must be positive", ErrInvalid)
	}
	token, err := helpers.RandomHexID(32)
	if err != nil {
		return Session{}, err
	}
	csrfToken, err := helpers.RandomHexID(32)
	if err != nil {
		return Session{}, err
	}
	now := time.Now().UTC()
	session := Session{
		Token:     token,
		CSRFToken: csrfToken,
		UserID:    userID,
		CreatedAt: now,
		ExpiresAt: now.Add(ttl),
	}
	err = store.db.Update(func(txn *badger.Txn) error {
		return putJSON(txn, sessionKey(token), session)
	})
	return session, err
}

func (store *Store) GetSession(token string) (Session, bool, error) {
	token = strings.TrimSpace(token)
	if token == "" {
		return Session{}, false, nil
	}

	var session Session
	err := store.db.View(func(txn *badger.Txn) error {
		return getJSON(txn, sessionKey(token), &session)
	})
	if errors.Is(err, ErrNotFound) {
		return Session{}, false, nil
	}
	if err != nil {
		return Session{}, false, err
	}
	if time.Now().UTC().After(session.ExpiresAt) {
		_ = store.DeleteSession(token)
		return Session{}, false, nil
	}
	return session, true, nil
}

func (store *Store) DeleteSession(token string) error {
	return store.db.Update(func(txn *badger.Txn) error {
		err := txn.Delete(sessionKey(token))
		if errors.Is(err, badger.ErrKeyNotFound) {
			return nil
		}
		return err
	})
}

func sessionKey(token string) []byte {
	return []byte("session/" + strings.TrimSpace(token))
}
