import type { Ticket } from '../models/ticket.ts'; import type { Transaction } from '../models/transaction.ts'; import { LifecycleValidator } from '../lifecycle/validator.ts'; import type { LifecycleDefinition } from '../lifecycle/validator.ts'; export interface ConditionEvaluateContext { lifecycleDef?: LifecycleDefinition; } export interface ConditionConfig { from_status?: unknown; to_status?: unknown; field_key?: unknown; field_id?: unknown; field?: unknown; old_value?: unknown; new_value?: unknown; value?: unknown; } export interface ConditionEvaluator { evaluate(ticket: Ticket, transactions: Transaction[], context?: ConditionEvaluateContext, config?: ConditionConfig): boolean; } function matchesStatusFilter(value: string | null, filter: unknown): boolean { if (filter === undefined || filter === null || filter === '') return true; if (value === null) return false; const normalizedValue = value.toLowerCase(); if (Array.isArray(filter)) { return filter.map((item) => String(item).toLowerCase()).includes(normalizedValue); } return normalizedValue === String(filter).toLowerCase(); } export class OnCreate implements ConditionEvaluator { evaluate(_ticket: Ticket, transactions: Transaction[]): boolean { return transactions.some((tx) => tx.transaction_type === 'Create'); } } export class OnStatusChange implements ConditionEvaluator { evaluate(_ticket: Ticket, transactions: Transaction[], _context?: ConditionEvaluateContext, config?: ConditionConfig): boolean { return transactions.some((tx) => tx.transaction_type === 'StatusChange' && matchesStatusFilter(tx.old_value, config?.from_status) && matchesStatusFilter(tx.new_value, config?.to_status) ); } } export class OnResolve implements ConditionEvaluator { private lifecycleValidator = new LifecycleValidator(); evaluate(_ticket: Ticket, transactions: Transaction[], context?: ConditionEvaluateContext, config?: ConditionConfig): boolean { const lifecycleDef = context?.lifecycleDef; return transactions.some((tx) => { if (tx.transaction_type !== 'StatusChange' || tx.new_value === null) return false; if (!matchesStatusFilter(tx.old_value, config?.from_status)) return false; if (!matchesStatusFilter(tx.new_value, config?.to_status)) return false; if (lifecycleDef) { return this.lifecycleValidator.isResolvedStatus(lifecycleDef, tx.new_value); } return ['resolved', 'closed', 'completed', 'rejected', 'cancelled'].includes(tx.new_value.toLowerCase()); }); } } export class OnCustomFieldChange implements ConditionEvaluator { evaluate(_ticket: Ticket, transactions: Transaction[], _context?: ConditionEvaluateContext, config?: ConditionConfig): boolean { const fieldFilter = config?.field_key ?? config?.field_id ?? config?.field; const newValueFilter = config?.new_value ?? config?.value; return transactions.some((tx) => tx.transaction_type === 'CustomFieldChange' && matchesStatusFilter(tx.field, fieldFilter) && matchesStatusFilter(tx.old_value, config?.old_value) && matchesStatusFilter(tx.new_value, newValueFilter) ); } } const conditionRegistry: Record = { OnCreate: new OnCreate(), OnStatusChange: new OnStatusChange(), OnResolve: new OnResolve(), OnCustomFieldChange: new OnCustomFieldChange(), }; export function getConditionEvaluator(type: string): ConditionEvaluator | null { return conditionRegistry[type] ?? null; } export { conditionRegistry };