package storage

import (
	"github.com/rs/zerolog/log"
	"gorm.io/gorm"

	"git.mstar.dev/mstar/linstrom/shared"
)

// Auto-generate string names for the various constants
//go:generate stringer -type InboundJobSource

type InboundJobSource int

// TODO: Adjust and expand these constants later, depending on sources
const (
	InJobSourceAccInbox InboundJobSource = iota
	InJobSourceServerInbox
	InJobSourceApiMasto
	InJobSourceApiLinstrom
)

// Store inbound jobs from api and ap in the db until they finished processing
// Ensures data consistency in case the server is forced to restart unexpectedly
// Inbound jobs must allways be processed in order from oldest to newest to ensure consistency
type InboundJob struct {
	gorm.Model
	// Raw data, could be json or gob data, check source for how to interpret
	RawData []byte `gorm:"->;<-create"`
	// Where this job is coming from. Important for figuring out how to decode the raw data and what to do with it
	Source InboundJobSource `gorm:"->;<-create"`

	// Section: Various data
	// TODO: Expand based on needs

	// If from an inbox, include the owner id here
	InboxOwner *string `gorm:"->;<-create"`
}

func (s *Storage) AddNewInboundJob(data []byte, source InboundJobSource, inboxOwner *string) {
	defer shared.Untrace(shared.Trace(&log.Logger))
	newJob := InboundJob{
		RawData:    data,
		Source:     source,
		InboxOwner: inboxOwner,
	}
	s.db.Create(&newJob)
}

// Get the specified amount of jobs, sorted by age (oldest first)
func (s *Storage) GetOldestInboundJobs(amount uint) ([]InboundJob, error) {
	defer shared.Untrace(shared.Trace(&log.Logger))
	jobs := []InboundJob{}
	switch err := s.db.Order("id asc, created_at asc").Limit(int(amount)).Find(jobs).Error; err {
	case gorm.ErrRecordNotFound:
		return nil, ErrEntryNotFound
	case nil:
		return jobs, nil
	default:
		return nil, err
	}
}

func (s *Storage) CompleteInboundJob(id uint) error {
	defer shared.Untrace(shared.Trace(&log.Logger))
	s.db.Delete(InboundJob{Model: gorm.Model{ID: id}})
	return nil
}
