package fifo_stock_v2

import (
	"context"
	"time"

	"gorm.io/gorm"
)

type Lane string

const (
	LaneStockable Lane = "STOCKABLE"
	LaneUsable    Lane = "USABLE"
)

type Operation string

const (
	OperationAllocate    Operation = "ALLOCATE"
	OperationRollback    Operation = "ROLLBACK"
	OperationReflow      Operation = "REFLOW"
	OperationRecalculate Operation = "RECALCULATE"
)

type Ref struct {
	Table         string
	ID            uint
	LegacyTypeKey string
	FunctionCode  string
}

type GatherRequest struct {
	FlagGroupCode      string
	Lane               Lane
	AllocationPurpose  string
	IgnoreSourceUsed   bool
	ProductWarehouseID uint
	From               *time.Time
	AsOf               *time.Time
	Limit              int
	AfterSortAt        *time.Time
	AfterSourceTable   string
	AfterSourceID      uint
	ForUpdate          bool
	Tx                 *gorm.DB
}

type GatherRow struct {
	Ref                Ref
	FlagGroupCode      string
	ProductWarehouseID uint
	SortAt             time.Time
	SortPriority       int
	Quantity           float64
	UsedQuantity       float64
	PendingQuantity    float64
	AvailableQuantity  float64
	SourceTable        string
	SourceID           uint
}

type AllocateRequest struct {
	FlagGroupCode      string
	ProductWarehouseID uint
	Usable             Ref
	NeedQty            float64
	AllowOverConsume   *bool
	IdempotencyKey     string
	AsOf               *time.Time
	Tx                 *gorm.DB
}

type AllocationDetail struct {
	StockableType string
	StockableID   uint
	Qty           float64
	SortAt        time.Time
}

type AllocateResult struct {
	AllocatedQty float64
	PendingQty   float64
	Details      []AllocationDetail
}

type RollbackRequest struct {
	ProductWarehouseID uint
	Usable             Ref
	ReleaseQty         *float64
	Reason             string
	IdempotencyKey     string
	Tx                 *gorm.DB
}

type RollbackResult struct {
	ReleasedQty float64
	Details     []AllocationDetail
}

type ReflowRequest struct {
	FlagGroupCode      string
	ProductWarehouseID uint
	AsOf               *time.Time
	IdempotencyKey     string
	Tx                 *gorm.DB
}

type ReflowResult struct {
	ProcessedUsables int
	Rollback         RollbackResult
	Allocate         AllocateResult
}

type RecalculateRequest struct {
	ProductWarehouseIDs []uint
	FlagGroupCodes      []string
	AsOf                *time.Time
	FixDrift            bool
	IdempotencyKey      string
	Tx                  *gorm.DB
}

type WarehouseDrift struct {
	ProductWarehouseID uint
	ExpectedQty        float64
	ActualQty          float64
	Delta              float64
}

type RecalculateResult struct {
	Checked int
	Fixed   int
	Drifts  []WarehouseDrift
}

type Service interface {
	Gather(ctx context.Context, req GatherRequest) ([]GatherRow, error)
	Allocate(ctx context.Context, req AllocateRequest) (*AllocateResult, error)
	Rollback(ctx context.Context, req RollbackRequest) (*RollbackResult, error)
	Reflow(ctx context.Context, req ReflowRequest) (*ReflowResult, error)
	Recalculate(ctx context.Context, req RecalculateRequest) (*RecalculateResult, error)
}
