package engine

import (
	"context"
	"sync/atomic"

	"git.difuse.io/Difuse/Mellaris/io"
	"git.difuse.io/Difuse/Mellaris/ruleset"
)

// Engine is the main engine for Mellaris.
type Engine interface {
	// UpdateRuleset updates the ruleset.
	UpdateRuleset(ruleset.Ruleset) error
	// Run runs the engine, until an error occurs or the context is cancelled.
	Run(context.Context) error
	// Stats returns a consistent snapshot of runtime counters.
	Stats() Stats
}

type OverflowPolicy string

const (
	OverflowPolicyAccept       OverflowPolicy = "accept"
	OverflowPolicyDrop         OverflowPolicy = "drop"
	OverflowPolicyBackpressure OverflowPolicy = "backpressure"
)

type AnalyzerSelectionMode string

const (
	AnalyzerSelectionModeAlways    AnalyzerSelectionMode = "always"
	AnalyzerSelectionModeSignature AnalyzerSelectionMode = "signature"
)

type statsCounters struct {
	OverflowEvents             atomic.Uint64
	OverflowAccepts            atomic.Uint64
	OverflowDrops              atomic.Uint64
	OverflowBackpressureEvents atomic.Uint64

	AnalyzerSelectionsTotal  atomic.Uint64
	AnalyzerSelectionsPruned atomic.Uint64

	UDPTupleLookups atomic.Uint64
	UDPTupleHits    atomic.Uint64
}

type Stats struct {
	OverflowEvents             uint64
	OverflowAccepts            uint64
	OverflowDrops              uint64
	OverflowBackpressureEvents uint64

	AnalyzerSelectionsTotal  uint64
	AnalyzerSelectionsPruned uint64

	UDPTupleLookups uint64
	UDPTupleHits    uint64
}

// Config is the configuration for the engine.
type Config struct {
	Logger  Logger
	IO      io.PacketIO
	Ruleset ruleset.Ruleset

	Workers                          int // Number of workers. Zero or negative means auto (number of CPU cores).
	WorkerQueueSize                  int
	WorkerTCPMaxBufferedPagesTotal   int
	WorkerTCPMaxBufferedPagesPerConn int
	WorkerUDPMaxStreams              int
	OverflowPolicy                   OverflowPolicy
	AnalyzerSelectionMode            AnalyzerSelectionMode
}

// Logger is the combined logging interface for the engine, workers and analyzers.
type Logger interface {
	WorkerStart(id int)
	WorkerStop(id int)

	TCPStreamNew(workerID int, info ruleset.StreamInfo)
	TCPStreamPropUpdate(info ruleset.StreamInfo, close bool)
	TCPStreamAction(info ruleset.StreamInfo, action ruleset.Action, noMatch bool)

	UDPStreamNew(workerID int, info ruleset.StreamInfo)
	UDPStreamPropUpdate(info ruleset.StreamInfo, close bool)
	UDPStreamAction(info ruleset.StreamInfo, action ruleset.Action, noMatch bool)

	ModifyError(info ruleset.StreamInfo, err error)

	AnalyzerDebugf(streamID int64, name string, format string, args ...interface{})
	AnalyzerInfof(streamID int64, name string, format string, args ...interface{})
	AnalyzerErrorf(streamID int64, name string, format string, args ...interface{})
}
