package utils

import (
	"slices"
	"strings"

	approvalutils "gitlab.com/mbugroup/lti-api.git/internal/utils/approvals"
)

// -------------------------------------------------------------------
// FlagType & Groups
// -------------------------------------------------------------------

type FlagType string

type FlagGroup string

type ProductFlagOption struct {
	Flag                FlagType   `json:"flag"`
	SubFlags            []FlagType `json:"sub_flags"`
	AllowWithoutSubFlag bool       `json:"allow_without_sub_flag"`
}

const (
	FlagIsActive FlagType = "IS_ACTIVE"

	FlagAyam FlagType = "AYAM"

	FlagDOC        FlagType = "DOC"
	FlagPullet     FlagType = "PULLET"
	FlagLayer      FlagType = "LAYER"
	FlagPakan      FlagType = "PAKAN"
	FlagPreStarter FlagType = "PRE-STARTER"
	FlagStarter    FlagType = "STARTER"
	FlagFinisher   FlagType = "FINISHER"
	FlagOVK        FlagType = "OVK"
	FlagObat       FlagType = "OBAT"
	FlagVitamin    FlagType = "VITAMIN"
	FlagKimia      FlagType = "KIMIA"
	FlagEkspedisi  FlagType = "EKSPEDISI"

	// flag ayam
	FlagAyamAfkir   FlagType = "AYAM-AFKIR"
	FlagAyamCulling FlagType = "AYAM-CULLING"
	FlagAyamMati    FlagType = "AYAM-MATI"

	//flag telur
	FlagTelur        FlagType = "TELUR"
	FlagTelurUtuh    FlagType = "TELUR-UTUH"
	FlagTelurPecah   FlagType = "TELUR-PECAH"
	FlagTelurPutih   FlagType = "TELUR-PUTIH"
	FlagTelurRetak   FlagType = "TELUR-RETAK"
	FlagTelurPapacal FlagType = "TELUR-PAPACAL"
	FlagTelurJumbo   FlagType = "TELUR-JUMBO"
)

const (
	FlagGroupProduct  FlagGroup = "PRODUCT"
	FlagGroupNonstock FlagGroup = "NONSTOCK"
)

var flagGroupOptions = map[FlagGroup][]FlagType{
	FlagGroupProduct: {
		FlagAyam,
		FlagAyamAfkir,
		FlagAyamCulling,
		FlagAyamMati,
		FlagPakan,
		FlagPreStarter,
		FlagStarter,
		FlagFinisher,
		FlagOVK,
		FlagObat,
		FlagVitamin,
		FlagKimia,
		FlagTelur,
		FlagTelurUtuh,
		FlagTelurPecah,
		FlagTelurPutih,
		FlagTelurRetak,
		FlagTelurPapacal,
		FlagTelurJumbo,
	},
	FlagGroupNonstock: {
		FlagEkspedisi,
	},
}

var productMainFlags = []FlagType{
	FlagAyam,
	FlagPakan,
	FlagOVK,
	FlagTelur,
}

var productSubFlagsByFlag = map[FlagType][]FlagType{
	FlagAyam: {
		FlagAyamAfkir,
		FlagAyamCulling,
		FlagAyamMati,
	},
	FlagPakan: {
		FlagPreStarter,
		FlagStarter,
		FlagFinisher,
	},
	FlagOVK: {
		FlagObat,
		FlagVitamin,
		FlagKimia,
	},
	FlagTelur: {
		FlagTelurUtuh,
		FlagTelurPutih,
		FlagTelurRetak,
		FlagTelurPecah,
		FlagTelurPapacal,
		FlagTelurJumbo,
	},
}

var productSubFlagToFlag = func() map[FlagType]FlagType {
	out := make(map[FlagType]FlagType)
	for flag, subFlags := range productSubFlagsByFlag {
		for _, subFlag := range subFlags {
			out[subFlag] = flag
		}
	}
	return out
}()

var productAllowWithoutSubFlagByFlag = map[FlagType]bool{
	FlagAyam:  true,
	FlagPakan: false,
	FlagOVK:   false,
	FlagTelur: false,
}

var legacyProductCategoryFlagsByCode = map[string][]FlagType{
	"DOC": {FlagAyam, FlagDOC},
	"PLT": {FlagAyam, FlagPullet},
	"EGG": {FlagTelur},
	"RAW": {FlagPakan},
	"PST": {FlagPakan, FlagPreStarter},
	"STR": {FlagPakan, FlagStarter},
	"FSR": {FlagPakan, FlagFinisher},
	"OBT": {FlagOVK, FlagObat},
	"VTM": {FlagOVK, FlagVitamin},
	"KMA": {FlagOVK, FlagKimia},
}

var legacyFlagTypeAliases = map[FlagType]FlagType{
	FlagDOC:    FlagAyam,
	FlagPullet: FlagAyam,
	FlagLayer:  FlagAyam,
}

var allFlagTypes = func() map[FlagType]struct{} {
	m := map[FlagType]struct{}{
		FlagIsActive: {},
	}
	for _, flags := range flagGroupOptions {
		for _, flag := range flags {
			m[flag] = struct{}{}
		}
	}
	return m
}()

func AllFlagTypes() map[FlagType]struct{} {
	return allFlagTypes
}

func canonicalizeFlagType(flag FlagType) FlagType {
	if canonical, ok := legacyFlagTypeAliases[flag]; ok {
		return canonical
	}
	return flag
}

func CanonicalFlagType(v string) FlagType {
	normalized := FlagType(strings.ToUpper(strings.TrimSpace(v)))
	if normalized == "" {
		return ""
	}
	return canonicalizeFlagType(normalized)
}

func LegacyFlagTypeAliases() map[FlagType]FlagType {
	out := make(map[FlagType]FlagType, len(legacyFlagTypeAliases))
	for legacy, canonical := range legacyFlagTypeAliases {
		out[legacy] = canonical
	}
	return out
}

func ProductMainFlags() []FlagType {
	out := make([]FlagType, len(productMainFlags))
	copy(out, productMainFlags)
	return out
}

func ProductSubFlagsByFlag() map[FlagType][]FlagType {
	out := make(map[FlagType][]FlagType, len(productSubFlagsByFlag))
	for flag, subFlags := range productSubFlagsByFlag {
		dup := make([]FlagType, len(subFlags))
		copy(dup, subFlags)
		out[flag] = dup
	}
	return out
}

func ProductSubFlagToFlag() map[FlagType]FlagType {
	out := make(map[FlagType]FlagType, len(productSubFlagToFlag))
	for subFlag, flag := range productSubFlagToFlag {
		out[subFlag] = flag
	}
	return out
}

func ProductFlagOptions() []ProductFlagOption {
	result := make([]ProductFlagOption, 0, len(productMainFlags))
	for _, flag := range productMainFlags {
		subFlags := productSubFlagsByFlag[flag]
		dup := make([]FlagType, len(subFlags))
		copy(dup, subFlags)
		result = append(result, ProductFlagOption{
			Flag:                flag,
			SubFlags:            dup,
			AllowWithoutSubFlag: productAllowWithoutSubFlagByFlag[flag],
		})
	}
	return result
}

func ProductFlagAllowWithoutSubFlag(flag FlagType) bool {
	canonical := canonicalizeFlagType(flag)
	allow, ok := productAllowWithoutSubFlagByFlag[canonical]
	if !ok {
		return false
	}
	return allow
}

func LegacyProductCategoryCodesForFlags(flags []string) []string {
	if len(flags) == 0 {
		return nil
	}

	requested := make(map[FlagType]struct{}, len(flags))
	for _, flag := range flags {
		canonical := CanonicalFlagType(flag)
		if canonical == "" {
			continue
		}
		requested[canonical] = struct{}{}
	}
	if len(requested) == 0 {
		return nil
	}

	codes := make([]string, 0, len(legacyProductCategoryFlagsByCode))
	for code, supportedFlags := range legacyProductCategoryFlagsByCode {
		for _, supportedFlag := range supportedFlags {
			if _, ok := requested[canonicalizeFlagType(supportedFlag)]; ok {
				codes = append(codes, code)
				break
			}
		}
	}

	slices.Sort(codes)
	return codes
}

func LegacyFlagGroupCodeByProductCategoryCode(code string) string {
	switch strings.ToUpper(strings.TrimSpace(code)) {
	case "DOC", "PLT":
		return "AYAM"
	case "EGG":
		return "TELUR"
	case "RAW", "PST", "STR", "FSR":
		return "PAKAN"
	case "OBT", "VTM", "KMA":
		return "OVK"
	default:
		return ""
	}
}

func IsProductMainFlag(flag FlagType) bool {
	canonical := canonicalizeFlagType(flag)
	for _, f := range productMainFlags {
		if f == canonical {
			return true
		}
	}
	return false
}

func IsValidProductSubFlag(flag FlagType, subFlag FlagType) bool {
	canonicalFlag := canonicalizeFlagType(flag)
	canonicalSubFlag := canonicalizeFlagType(subFlag)
	allowedSubFlags, ok := productSubFlagsByFlag[canonicalFlag]
	if !ok {
		return false
	}
	for _, allowed := range allowedSubFlags {
		if allowed == canonicalSubFlag {
			return true
		}
	}
	return false
}

// -------------------------------------------------------------------
// WarehouseType
// -------------------------------------------------------------------

type WarehouseType string

const (
	WarehouseTypeArea    WarehouseType = "AREA"
	WarehouseTypeLokasi  WarehouseType = "LOKASI"
	WarehouseTypeKandang WarehouseType = "KANDANG"
)

// -------------------------------------------------------------------
// Stock log
// -------------------------------------------------------------------

type StockLogTransactionType string

const (
	StockLogTransactionTypeIncrease StockLogTransactionType = "INCREASE"
	StockLogTransactionTypeDecrease StockLogTransactionType = "DECREASE"
)

type StockLogType string

const (
	StockLogTypeAdjustment     StockLogType = "ADJUSTMENT"
	StockLogTypeTransfer       StockLogType = "TRANSFER"
	StockLogTypeTransferLaying StockLogType = "TRANSFER_LAYING"
	StockLogTypeMarketing      StockLogType = "MARKETING"
	StockLogTypeChikin         StockLogType = "CHICKIN"
	StockLogTypePurchase       StockLogType = "PURCHASE"
	StockLogTypeRecording      StockLogType = "RECORDING"
)

// -------------------------------------------------------------------
// Transfer context
// -------------------------------------------------------------------

const (
	TransferContextKey               = "transfer_context"
	TransferContextInventoryTransfer = "inventory_transfer"
	TransferContextTransferToLaying  = "transfer_to_laying"
)

// -------------------------------------------------------------------
// WarehouseType
// -------------------------------------------------------------------

type CustomerSupplierType string

const (
	CustomerSupplierTypeBisnis     CustomerSupplierType = "BISNIS"
	CustomerSupplierTypeIndividual CustomerSupplierType = "INDIVIDUAL"
)

// -------------------------------------------------------------------
// SupplierCategory
// -------------------------------------------------------------------

type SupplierCategory string

const (
	SupplierCategoryBOP      SupplierCategory = "BOP"
	SupplierCategorySapronak SupplierCategory = "SAPRONAK"
)

// -------------------------------------------------------------------
// ExpenseCategory
// -------------------------------------------------------------------

type ExpenseCategory string

const (
	ExpenseCategoryBOP    ExpenseCategory = "BOP"
	ExpenseCategoryNonBOP ExpenseCategory = "NON-BOP"
)

// -------------------------------------------------------------------
// Filter Customer Payment
// -------------------------------------------------------------------

const (
	CustomerPaymentFilterByTransDate       = "TRANS_DATE"
	CustomerPaymentFilterByRealizationDate = "REALIZATION_DATE"
)

// -------------------------------------------------------------------
// Payment Method
// -------------------------------------------------------------------

type PaymentMethod string

const (
	PaymentMethodTransfer PaymentMethod = "TRANSFER"
	PaymentMethodCash     PaymentMethod = "CASH"
	PaymentMethodCard     PaymentMethod = "CARD"
	PaymentMethodCheque   PaymentMethod = "CHEQUE"
	PaymentMethodSaldo    PaymentMethod = "SALDO"
)

// -------------------------------------------------------------------
// Trasaction Type
// -------------------------------------------------------------------

type TransactionType string

const (
	TransactionTypePenjualan TransactionType = "PENJUALAN"
	TransactionTypePembelian TransactionType = "PEMBELIAN"
	TransactionTypeBiaya     TransactionType = "BIAYA"
	TransactionTypeInjection TransactionType = "INJECTION"
	TransactionTypeSaldoAwal TransactionType = "SALDO_AWAL"
)

type AdjustmentTransactionType string

const (
	AdjustmentTransactionTypePembelian AdjustmentTransactionType = "PEMBELIAN"
	AdjustmentTransactionTypeRecording AdjustmentTransactionType = "RECORDING"
	AdjustmentTransactionTypePenjualan AdjustmentTransactionType = "PENJUALAN"
)

type AdjustmentTransactionSubtype string

const (
	AdjustmentTransactionSubtypePurchaseIn            AdjustmentTransactionSubtype = "PURCHASE_IN"
	AdjustmentTransactionSubtypeRecordingDepletionOut AdjustmentTransactionSubtype = "RECORDING_DEPLETION_OUT"
	AdjustmentTransactionSubtypeMarketingOut          AdjustmentTransactionSubtype = "MARKETING_OUT"
	AdjustmentTransactionSubtypeRecordingDepletionIn  AdjustmentTransactionSubtype = "RECORDING_DEPLETION_IN"
	AdjustmentTransactionSubtypeRecordingStockOut     AdjustmentTransactionSubtype = "RECORDING_STOCK_OUT"
	AdjustmentTransactionSubtypeRecordingEggIn        AdjustmentTransactionSubtype = "RECORDING_EGG_IN"
)

var adjustmentSubtypesByType = map[AdjustmentTransactionType][]string{
	AdjustmentTransactionTypePembelian: {
		string(AdjustmentTransactionSubtypePurchaseIn),
	},
	AdjustmentTransactionTypeRecording: {
		string(AdjustmentTransactionSubtypeRecordingStockOut),
		string(AdjustmentTransactionSubtypeRecordingDepletionOut),
		string(AdjustmentTransactionSubtypeRecordingDepletionIn),
		string(AdjustmentTransactionSubtypeRecordingEggIn),
	},
	AdjustmentTransactionTypePenjualan: {
		string(AdjustmentTransactionSubtypeMarketingOut),
	},
}

var hiddenAdjustmentSubtypesForFrontend = map[string]struct{}{
	string(AdjustmentTransactionSubtypeRecordingDepletionOut): {},
}

var adjustmentSubtypeToType = func() map[string]AdjustmentTransactionType {
	out := make(map[string]AdjustmentTransactionType)
	for txType, subtypes := range adjustmentSubtypesByType {
		for _, subtype := range subtypes {
			code := strings.ToUpper(strings.TrimSpace(subtype))
			if code == "" {
				continue
			}
			out[code] = txType
		}
	}
	return out
}()

func AdjustmentTransactionTypes() []string {
	return []string{
		string(AdjustmentTransactionTypePembelian),
		string(AdjustmentTransactionTypeRecording),
		string(AdjustmentTransactionTypePenjualan),
	}
}

func AdjustmentTransactionSubtypesByType() map[string][]string {
	out := make(map[string][]string, len(adjustmentSubtypesByType))
	for _, txType := range []AdjustmentTransactionType{
		AdjustmentTransactionTypePembelian,
		AdjustmentTransactionTypeRecording,
		AdjustmentTransactionTypePenjualan,
	} {
		src := adjustmentSubtypesByType[txType]
		dup := make([]string, len(src))
		copy(dup, src)
		out[string(txType)] = dup
	}
	return out
}

func AdjustmentTransactionSubtypes() []string {
	result := make([]string, 0)
	for _, txType := range []AdjustmentTransactionType{
		AdjustmentTransactionTypePembelian,
		AdjustmentTransactionTypeRecording,
		AdjustmentTransactionTypePenjualan,
	} {
		result = append(result, adjustmentSubtypesByType[txType]...)
	}
	return result
}

func AdjustmentTransactionSubtypesByTypeForFrontend() map[string][]string {
	out := make(map[string][]string, len(adjustmentSubtypesByType))
	for txType, subtypes := range AdjustmentTransactionSubtypesByType() {
		filtered := make([]string, 0, len(subtypes))
		for _, subtype := range subtypes {
			if _, hidden := hiddenAdjustmentSubtypesForFrontend[subtype]; hidden {
				continue
			}
			filtered = append(filtered, subtype)
		}
		out[txType] = filtered
	}
	return out
}

func AdjustmentTransactionSubtypesForFrontend() []string {
	result := make([]string, 0)
	for _, subtype := range AdjustmentTransactionSubtypes() {
		if _, hidden := hiddenAdjustmentSubtypesForFrontend[subtype]; hidden {
			continue
		}
		result = append(result, subtype)
	}
	return result
}

func ResolveAdjustmentTransactionType(functionCode string) string {
	code := strings.ToUpper(strings.TrimSpace(functionCode))
	if txType, ok := adjustmentSubtypeToType[code]; ok {
		return string(txType)
	}
	switch {
	case strings.HasPrefix(code, "PURCHASE_"):
		return string(AdjustmentTransactionTypePembelian)
	case strings.HasPrefix(code, "MARKETING_"):
		return string(AdjustmentTransactionTypePenjualan)
	case strings.HasPrefix(code, "RECORDING_"):
		return string(AdjustmentTransactionTypeRecording)
	default:
		return ""
	}
}

// -------------------------------------------------------------------
// Payment Party
// -------------------------------------------------------------------

type PaymentParty string

const (
	PaymentPartyCustomer PaymentParty = "CUSTOMER"
	PaymentPartySupplier PaymentParty = "SUPPLIER"
)

// -------------------------------------------------------------------
// Kandang Status
// -------------------------------------------------------------------

type KandangStatus string

const (
	KandangStatusNonActive KandangStatus = "NON_ACTIVE"
	KandangStatusPengajuan KandangStatus = "PENGAJUAN"
	KandangStatusActive    KandangStatus = "ACTIVE"
)

// -------------------------------------------------------------------
// House Type
// -------------------------------------------------------------------

type HouseType string

const (
	HouseTypeOpenHouse  HouseType = "open_house"
	HouseTypeCloseHouse HouseType = "close_house"
)

// -------------------------------------------------------------------
// Marketing Type
// -------------------------------------------------------------------

type MarketingType string

const (
	MarketingTypeAyam       MarketingType = "AYAM"
	MarketingTypeTelur      MarketingType = "TELUR"
	MarketingTypeTrading    MarketingType = "TRADING"
	MarketingTypeAyamPullet MarketingType = "AYAM_PULLET"
)

// -------------------------------------------------------------------
// Convertion Unit
// -------------------------------------------------------------------

type ConvertionUnit string

const (
	ConvertionUnitPeti ConvertionUnit = "PETI"
	ConvertionUnitKG   ConvertionUnit = "KG"
	ConvertionUnitQty  ConvertionUnit = "QTY"
)

// -------------------------------------------------------------------
// ProjectFlockCategory
// -------------------------------------------------------------------

type ProjectFlockCategory string

const (
	ProjectFlockCategoryGrowing ProjectFlockCategory = "GROWING"
	ProjectFlockCategoryLaying  ProjectFlockCategory = "LAYING"
)

// -------------------------------------------------------------------
// Project Flock Approval
// -------------------------------------------------------------------

const (
	ApprovalWorkflowProjectFlock approvalutils.ApprovalWorkflowKey = approvalutils.ApprovalWorkflowKey("PROJECT_FLOCKS")
	ProjectFlockStepPengajuan    approvalutils.ApprovalStep        = 1
	ProjectFlockStepAktif        approvalutils.ApprovalStep        = 2
	ProjectFlockStepSelesai      approvalutils.ApprovalStep        = 3
)

// projectFlockApprovalSteps keeps the workflow step definitions for project flock approvals.
var ProjectFlockApprovalSteps = map[approvalutils.ApprovalStep]string{
	ProjectFlockStepPengajuan: "Pengajuan",
	ProjectFlockStepAktif:     "Aktif",
	ProjectFlockStepSelesai:   "Selesai",
}

// -------------------------------------------------------------------
// Chickin Approval
// -------------------------------------------------------------------
const (
	ApprovalWorkflowChickin approvalutils.ApprovalWorkflowKey = approvalutils.ApprovalWorkflowKey("CHICKINS")
	ChickinStepPengajuan    approvalutils.ApprovalStep        = 1
	ChickinStepDisetujui    approvalutils.ApprovalStep        = 2
)

var ChickinApprovalSteps = map[approvalutils.ApprovalStep]string{
	ChickinStepPengajuan: "Pengajuan",
	ChickinStepDisetujui: "Disetujui",
}

// -------------------------------------------------------------------
// Project-Flock kandang Approval
// -------------------------------------------------------------------
const (
	ApprovalWorkflowProjectFlockKandang approvalutils.ApprovalWorkflowKey = approvalutils.ApprovalWorkflowKey("PROJECT_FLOCK_KANDANGS")
	ProjectFlockKandangStepPengajuan    approvalutils.ApprovalStep        = 1
	ProjectFlockKandangStepDisetujui    approvalutils.ApprovalStep        = 2
	ProjectFlockKandangStepClosed       approvalutils.ApprovalStep        = 3
)

var ProjectFlockKandangApprovalSteps = map[approvalutils.ApprovalStep]string{
	ProjectFlockKandangStepPengajuan: "Pengajuan",
	ProjectFlockKandangStepDisetujui: "Disetujui",
	ProjectFlockKandangStepClosed:    "Selesai",
}

// -------------------------------------------------------------------
// Transfer To laying Approval
// -------------------------------------------------------------------
const (
	ApprovalWorkflowTransferToLaying approvalutils.ApprovalWorkflowKey = approvalutils.ApprovalWorkflowKey("TRANSFER_TO_LAYINGS")
	TransferToLayingStepPengajuan    approvalutils.ApprovalStep        = 1
	TransferToLayingStepDisetujui    approvalutils.ApprovalStep        = 2
)

var TransferToLayingApprovalSteps = map[approvalutils.ApprovalStep]string{
	TransferToLayingStepPengajuan: "Pengajuan",
	TransferToLayingStepDisetujui: "Disetujui",
}

// -------------------------------------------------------------------

// -------------------------------------------------------------------
// Recording Approval
// -------------------------------------------------------------------

const (
	ApprovalWorkflowRecording approvalutils.ApprovalWorkflowKey = approvalutils.ApprovalWorkflowKey("RECORDINGS")
	RecordingStepPengajuan    approvalutils.ApprovalStep        = 1
	RecordingStepDisetujui    approvalutils.ApprovalStep        = 2
)

var RecordingApprovalSteps = map[approvalutils.ApprovalStep]string{
	RecordingStepPengajuan: "Pengajuan",
	RecordingStepDisetujui: "Disetujui",
}

// -------------------------------------------------------------------
// Uniformity Approval
// -------------------------------------------------------------------

const (
	ApprovalWorkflowUniformity approvalutils.ApprovalWorkflowKey = approvalutils.ApprovalWorkflowKey("UNIFORMITIES")
	UniformityStepPengajuan    approvalutils.ApprovalStep        = 1
	UniformityStepDisetujui    approvalutils.ApprovalStep        = 2
)

var UniformityApprovalSteps = map[approvalutils.ApprovalStep]string{
	UniformityStepPengajuan: "Pengajuan",
	UniformityStepDisetujui: "Disetujui",
}

// -------------------------------------------------------------------
// Purchase Approval
// -------------------------------------------------------------------

const (
	ApprovalWorkflowPurchase  approvalutils.ApprovalWorkflowKey = approvalutils.ApprovalWorkflowKey("PURCHASES")
	PurchaseStepPengajuan     approvalutils.ApprovalStep        = 1
	PurchaseStepStaffPurchase approvalutils.ApprovalStep        = 2
	PurchaseStepManager       approvalutils.ApprovalStep        = 3
	PurchaseStepReceiving     approvalutils.ApprovalStep        = 4
	PurchaseStepCompleted     approvalutils.ApprovalStep        = 5

	PurchasePRNumberPrefix      = "PR-LTI-"
	PurchasePONumberPrefix      = "PO-LTI-"
	AdjustmentStockNumberPrefix = "ADJ-"
	PurchaseNumberPadding       = 4
)

var PurchaseApprovalSteps = map[approvalutils.ApprovalStep]string{
	PurchaseStepPengajuan:     "Pengajuan",
	PurchaseStepStaffPurchase: "Staff Purchase",
	PurchaseStepManager:       "Manager Purchase",
	PurchaseStepReceiving:     "Penerimaan Produk",
	PurchaseStepCompleted:     "Selesai",
}

// -------------------------------------------------------------------
// Marketings Approval
// -------------------------------------------------------------------

const (
	ApprovalWorkflowMarketing approvalutils.ApprovalWorkflowKey = approvalutils.ApprovalWorkflowKey("MARKETINGS")
	MarketingStepPengajuan    approvalutils.ApprovalStep        = 1
	MarketingStepSalesOrder   approvalutils.ApprovalStep        = 2
	MarketingDeliveryOrder    approvalutils.ApprovalStep        = 3

	MarketingSoNumberPrefix = "SO-"
	MarketingNumberPadding  = 5
)

var MarketingApprovalSteps = map[approvalutils.ApprovalStep]string{
	MarketingStepPengajuan:  "Pengajuan",
	MarketingStepSalesOrder: "Sales Order",
	MarketingDeliveryOrder:  "Delivery Order",
}

// -------------------------------------------------------------------
// Expense Approval
// -------------------------------------------------------------------

const (
	ApprovalWorkflowExpense      approvalutils.ApprovalWorkflowKey = approvalutils.ApprovalWorkflowKey("EXPENSES")
	ExpenseStepPengajuan         approvalutils.ApprovalStep        = 1
	ExpenseStepHeadArea          approvalutils.ApprovalStep        = 2
	ExpenseStepUnitVicePresident approvalutils.ApprovalStep        = 3
	ExpenseStepFinance           approvalutils.ApprovalStep        = 4
	ExpenseStepRealisasi         approvalutils.ApprovalStep        = 5
	ExpenseStepSelesai           approvalutils.ApprovalStep        = 6
)

var ExpenseApprovalSteps = map[approvalutils.ApprovalStep]string{
	ExpenseStepPengajuan:         "Pengajuan",
	ExpenseStepHeadArea:          "Approval Head Area",
	ExpenseStepUnitVicePresident: "Approval Business Unit Vice President",
	ExpenseStepFinance:           "Approval Finance",
	ExpenseStepRealisasi:         "Realisasi",
	ExpenseStepSelesai:           "Selesai",
}

// -------------------------------------------------------------------
// Payment Approval
// -------------------------------------------------------------------

const (
	ApprovalWorkflowPayment approvalutils.ApprovalWorkflowKey = approvalutils.ApprovalWorkflowKey("PAYMENTS")
	PaymentStepPengajuan    approvalutils.ApprovalStep        = 1
	PaymentStepDisetujui    approvalutils.ApprovalStep        = 2
)

var PaymentApprovalSteps = map[approvalutils.ApprovalStep]string{
	PaymentStepPengajuan: "Pengajuan",
	PaymentStepDisetujui: "Disetujui",
}

// -------------------------------------------------------------------
// Inisial Balance Approval
// -------------------------------------------------------------------

const (
	ApprovalWorkflowInitial approvalutils.ApprovalWorkflowKey = approvalutils.ApprovalWorkflowKey("INITIAL_BALANCES")
	InitialStepPengajuan    approvalutils.ApprovalStep        = 1
	InitialStepDisetujui    approvalutils.ApprovalStep        = 2
)

var InitialApprovalSteps = map[approvalutils.ApprovalStep]string{
	InitialStepPengajuan: "Pengajuan",
	InitialStepDisetujui: "Disetujui",
}

// -------------------------------------------------------------------
// Injection Approval
// -------------------------------------------------------------------

const (
	ApprovalWorkflowInjection approvalutils.ApprovalWorkflowKey = approvalutils.ApprovalWorkflowKey("INJECTIONS")
	InjectionStepPengajuan    approvalutils.ApprovalStep        = 1
	InjectionStepDisetujui    approvalutils.ApprovalStep        = 2
)

var InjectionApprovalSteps = map[approvalutils.ApprovalStep]string{
	InjectionStepPengajuan: "Pengajuan",
	InjectionStepDisetujui: "Disetujui",
}

// -------------------------------------------------------------------
// Document
// -------------------------------------------------------------------

type DocumentType string
type DocumentableType string

const (
	DocumentTypeTransfer           DocumentType = "STOCK_TRANSFER_DOCUMENT"
	DocumentTypeExpense            DocumentType = "EXPENSE_DOCUMENT"
	DocumentTypeExpenseRealization DocumentType = "EXPENSE_REALIZATION_DOCUMENT"
	DocumentTypePurchaseTravel     DocumentType = "PURCHASE_TRAVEL_DOCUMENT"

	DocumentableTypeTransfer           DocumentableType = "STOCK_TRANSFER"
	DocumentableTypeExpense            DocumentableType = "EXPENSE"
	DocumentableTypeExpenseRealization DocumentableType = "EXPENSE_REALIZATION"
	DocumentableTypePurchaseItem       DocumentableType = "PURCHASE_ITEM"

	DocumentTypeDailyChecklist DocumentType = "DAILY_CHECKLIST_DOCUMENT"
)

// -------------------------------------------------------------------
// Validators
// -------------------------------------------------------------------

func IsValidFlagType(v string) bool {
	flag := FlagType(strings.ToUpper(strings.TrimSpace(v)))
	if _, ok := allFlagTypes[flag]; ok {
		return true
	}
	_, ok := legacyFlagTypeAliases[flag]
	return ok
}

func AllowedFlagTypes(group FlagGroup) []FlagType {
	options, ok := flagGroupOptions[group]
	if !ok {
		return nil
	}
	result := make([]FlagType, len(options))
	copy(result, options)
	return result
}

func InvalidFlagsForGroup(flags []FlagType, group FlagGroup) []FlagType {
	if len(flags) == 0 {
		return nil
	}
	options, ok := flagGroupOptions[group]
	if !ok {
		return flags
	}
	allowed := make(map[FlagType]struct{}, len(options))
	for _, flag := range options {
		allowed[flag] = struct{}{}
	}
	invalid := make([]FlagType, 0)
	for _, flag := range flags {
		if _, ok := allowed[flag]; !ok {
			invalid = append(invalid, flag)
		}
	}
	return invalid
}

func NormalizeFlagTypes(flags []string) []FlagType {
	if len(flags) == 0 {
		return nil
	}
	seen := make(map[FlagType]struct{}, len(flags))
	result := make([]FlagType, 0, len(flags))
	for _, flag := range flags {
		normalized := FlagType(strings.ToUpper(strings.TrimSpace(flag)))
		if normalized == "" {
			continue
		}
		normalized = canonicalizeFlagType(normalized)
		if _, exists := seen[normalized]; exists {
			continue
		}
		seen[normalized] = struct{}{}
		result = append(result, normalized)
	}
	if len(result) == 0 {
		return nil
	}
	return result
}

func FlagTypesToStrings(flags []FlagType) []string {
	if len(flags) == 0 {
		return nil
	}
	result := make([]string, len(flags))
	for i, flag := range flags {
		result[i] = string(flag)
	}
	return result
}

func NormalizeFlagsForGroup(raw []string, group FlagGroup) (normalized []FlagType, invalid []FlagType) {
	normalized = NormalizeFlagTypes(raw)
	if len(normalized) == 0 {
		return nil, nil
	}
	invalid = InvalidFlagsForGroup(normalized, group)
	if len(invalid) == 0 {
		return normalized, nil
	}
	return normalized, invalid
}

func IsValidWarehouseType(v string) bool {
	switch WarehouseType(v) {
	case WarehouseTypeArea, WarehouseTypeLokasi, WarehouseTypeKandang:
		return true
	}
	return false
}

func IsValidKandangStatus(v string) bool {
	switch KandangStatus(v) {
	case KandangStatusNonActive, KandangStatusPengajuan, KandangStatusActive:
		return true
	}
	return false
}

func IsValidCustomerSupplierType(v string) bool {
	switch CustomerSupplierType(v) {
	case CustomerSupplierTypeBisnis, CustomerSupplierTypeIndividual:
		return true
	}
	return false
}

func IsValidProjectFlockCategory(v string) bool {
	switch ProjectFlockCategory(v) {
	case ProjectFlockCategoryGrowing, ProjectFlockCategoryLaying:
		return true
	}
	return false
}

func IsValidSupplierCategory(v string) bool {
	switch SupplierCategory(v) {
	case SupplierCategoryBOP, SupplierCategorySapronak:
		return true
	}
	return false
}

func IsValidExpenseCategory(v string) bool {
	switch ExpenseCategory(v) {
	case ExpenseCategoryBOP, ExpenseCategoryNonBOP:
		return true
	}
	return false
}

func IsValidPaymentMethod(v string) bool {
	switch PaymentMethod(v) {
	case PaymentMethodTransfer, PaymentMethodCash, PaymentMethodCard, PaymentMethodCheque, PaymentMethodSaldo:
		return true
	}
	return false
}

func IsValidTransactionType(v string) bool {
	switch TransactionType(v) {
	case TransactionTypePenjualan, TransactionTypePembelian, TransactionTypeBiaya, TransactionTypeInjection, TransactionTypeSaldoAwal:
		return true
	}
	return false
}

func IsValidPaymentParty(v string) bool {
	switch PaymentParty(v) {
	case PaymentPartyCustomer, PaymentPartySupplier:
		return true
	}
	return false
}

func IsValidMarketingType(v string) bool {
	switch MarketingType(v) {
	case MarketingTypeAyam, MarketingTypeTelur, MarketingTypeTrading, MarketingTypeAyamPullet:
		return true
	}
	return false
}

func IsValidConvertionUnit(v string) bool {
	switch ConvertionUnit(v) {
	case ConvertionUnitPeti, ConvertionUnitKG, ConvertionUnitQty:
		return true
	}
	return false
}

// example use

// Recording helper

/**
if !utils.IsValidFlagType(req.FlagName) {
    return fiber.NewError(fiber.StatusBadRequest, "Invalid flag type")
}
*/
