"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.stateMachineService = exports.StateMachineService = exports.taskStatusMachine = void 0;
const xstate_1 = require("xstate");
const directus_client_1 = require("../../scripts/utils/directus-client");
// Import Directus SDK functions
const directusSdk = require('@directus/sdk');
const readItem = directusSdk.readItem;
const updateItem = directusSdk.updateItem;
/**
 * Task Status State Machine
 * Manages all valid state transitions for tasks
 */
exports.taskStatusMachine = (0, xstate_1.createMachine)({
    id: 'taskStatus',
    initial: 'draft',
    context: {
        taskId: '',
        currentStatus: 'draft',
        timestamp: new Date().toISOString()
    },
    states: {
        draft: {
            on: {
                START: {
                    target: 'todo',
                    actions: ['logTransition', 'updateTaskInDatabase']
                },
                CANCEL: {
                    target: 'cancelled',
                    actions: ['logTransition', 'updateTaskInDatabase']
                }
            }
        },
        todo: {
            on: {
                ASSIGN: {
                    target: 'in_progress',
                    actions: ['assignTask', 'logTransition', 'updateTaskInDatabase']
                },
                START: {
                    target: 'in_progress',
                    actions: ['logTransition', 'updateTaskInDatabase']
                },
                BLOCK: {
                    target: 'blocked',
                    actions: ['logTransition', 'updateTaskInDatabase']
                },
                DEFER: {
                    target: 'deferred',
                    actions: ['logTransition', 'updateTaskInDatabase']
                },
                CANCEL: {
                    target: 'cancelled',
                    actions: ['logTransition', 'updateTaskInDatabase']
                }
            }
        },
        in_progress: {
            on: {
                COMPLETE: {
                    target: 'review',
                    actions: ['logTransition', 'updateTaskInDatabase']
                },
                BLOCK: {
                    target: 'blocked',
                    actions: ['logTransition', 'updateTaskInDatabase']
                },
                DEFER: {
                    target: 'deferred',
                    actions: ['logTransition', 'updateTaskInDatabase']
                },
                CANCEL: {
                    target: 'cancelled',
                    actions: ['logTransition', 'updateTaskInDatabase']
                }
            }
        },
        review: {
            on: {
                APPROVE: {
                    target: 'done',
                    actions: ['logTransition', 'updateTaskInDatabase']
                },
                REJECT: {
                    target: 'in_progress',
                    actions: ['logTransition', 'updateTaskInDatabase']
                },
                BLOCK: {
                    target: 'blocked',
                    actions: ['logTransition', 'updateTaskInDatabase']
                }
            }
        },
        done: {
            on: {
                REOPEN: {
                    target: 'in_progress',
                    actions: ['logTransition', 'updateTaskInDatabase']
                },
                ARCHIVE: {
                    target: 'archived',
                    actions: ['logTransition', 'updateTaskInDatabase']
                }
            }
        },
        blocked: {
            on: {
                UNBLOCK: {
                    target: 'in_progress',
                    actions: ['logTransition', 'updateTaskInDatabase']
                },
                CANCEL: {
                    target: 'cancelled',
                    actions: ['logTransition', 'updateTaskInDatabase']
                }
            }
        },
        deferred: {
            on: {
                START: {
                    target: 'in_progress',
                    actions: ['logTransition', 'updateTaskInDatabase']
                },
                CANCEL: {
                    target: 'cancelled',
                    actions: ['logTransition', 'updateTaskInDatabase']
                }
            }
        },
        cancelled: {
            on: {
                REOPEN: {
                    target: 'todo',
                    actions: ['logTransition', 'updateTaskInDatabase']
                }
            }
        },
        archived: {
            type: 'final'
        }
    }
});
/**
 * State Machine Service
 * Manages state machine instances and persistence
 */
class StateMachineService {
    constructor() {
        this.machines = new Map();
        this.initializeClient();
    }
    async initializeClient() {
        this.client = await (0, directus_client_1.getAuthenticatedClient)();
    }
    /**
     * Get or create a state machine instance for a task
     */
    async getStateMachine(taskId) {
        if (this.machines.has(taskId)) {
            return this.machines.get(taskId);
        }
        if (!this.client)
            await this.initializeClient();
        // Fetch current task status from database
        const task = await this.client.request(readItem('tasks', taskId));
        // Get the current state from the task's workflow status
        const currentState = this.mapStatusToState(task.status);
        // Create machine with actions
        const machineWithActions = exports.taskStatusMachine.withConfig({
            actions: {
                logTransition: (context, event) => {
                    console.log(`Task ${context.taskId}: ${context.currentStatus} -> ${event.type}`);
                    this.logTransition(context, event);
                },
                updateTaskInDatabase: async (context, event) => {
                    await this.updateTaskStatus(context, event);
                },
                assignTask: (context, event) => {
                    if (event.assigneeId) {
                        context.metadata = { ...context.metadata, assigneeId: event.assigneeId };
                    }
                }
            }
        });
        // Create and start the service with restored state
        const service = (0, xstate_1.interpret)(machineWithActions)
            .start(currentState);
        // Store the service instance
        this.machines.set(taskId, service);
        return service;
    }
    /**
     * Map database status to state machine state
     */
    mapStatusToState(statusId) {
        // This would map Directus status IDs to state machine states
        // For now, returning a default mapping
        const statusMap = {
            'draft': 'draft',
            'todo': 'todo',
            'in_progress': 'in_progress',
            'review': 'review',
            'done': 'done',
            'blocked': 'blocked',
            'deferred': 'deferred',
            'cancelled': 'cancelled',
            'archived': 'archived'
        };
        return statusMap[statusId] || 'draft';
    }
    /**
     * Validate if a transition is allowed
     */
    async canTransition(taskId, event) {
        const machine = await this.getStateMachine(taskId);
        const nextState = machine.transition(machine.state, event);
        return nextState.changed;
    }
    /**
     * Execute a state transition
     */
    async transition(taskId, event) {
        const machine = await this.getStateMachine(taskId);
        // Check if transition is valid
        if (!await this.canTransition(taskId, event)) {
            throw new Error(`Invalid transition: ${event.type} from current state`);
        }
        // Send the event to trigger transition
        machine.send(event);
        return machine.state;
    }
    /**
     * Get current state for a task
     */
    async getCurrentState(taskId) {
        const machine = await this.getStateMachine(taskId);
        return machine.state;
    }
    /**
     * Get available transitions from current state
     */
    async getAvailableTransitions(taskId) {
        const machine = await this.getStateMachine(taskId);
        const state = machine.state;
        // Get all possible events for current state
        const stateNode = machine.machine.states[state.value];
        if (stateNode && stateNode.on) {
            return Object.keys(stateNode.on);
        }
        return [];
    }
    /**
     * Log state transition to audit log
     */
    async logTransition(context, event) {
        if (!this.client)
            await this.initializeClient();
        try {
            // Create audit log entry
            const auditLog = {
                task_id: context.taskId,
                from_status: context.previousStatus || context.currentStatus,
                to_status: event.type.toLowerCase(),
                event_type: event.type,
                event_data: JSON.stringify(event),
                user_id: context.userId,
                timestamp: new Date().toISOString(),
                metadata: context.metadata
            };
            // This would write to an audit log collection
            // await this.client.request(createItem('task_audit_logs', auditLog));
            console.log('Audit log:', auditLog);
        }
        catch (error) {
            console.error('Failed to log transition:', error);
        }
    }
    /**
     * Update task status in database
     */
    async updateTaskStatus(context, event) {
        if (!this.client)
            await this.initializeClient();
        try {
            const newStatus = this.mapEventToStatus(event.type);
            await this.client.request(updateItem('tasks', context.taskId, {
                status: newStatus,
                updated_at: new Date().toISOString(),
                workflow_metadata: {
                    last_transition: event.type,
                    transition_timestamp: new Date().toISOString(),
                    transition_user: context.userId
                }
            }));
        }
        catch (error) {
            console.error('Failed to update task status:', error);
            throw error;
        }
    }
    /**
     * Map event type to database status
     */
    mapEventToStatus(eventType) {
        const eventMap = {
            'START': 'in_progress',
            'COMPLETE': 'review',
            'APPROVE': 'done',
            'REJECT': 'in_progress',
            'BLOCK': 'blocked',
            'UNBLOCK': 'in_progress',
            'CANCEL': 'cancelled',
            'REOPEN': 'todo',
            'DEFER': 'deferred',
            'ARCHIVE': 'archived'
        };
        return eventMap[eventType] || 'draft';
    }
    /**
     * Persist state machine state
     */
    async persistState(taskId) {
        const machine = this.machines.get(taskId);
        if (!machine)
            return;
        const state = machine.state;
        // Store state in database or cache
        // This could be stored in Redis or database for recovery
        const stateData = {
            taskId,
            state: state.value,
            context: state.context,
            timestamp: new Date().toISOString()
        };
        // For now, just log it
        console.log('Persisting state:', stateData);
    }
    /**
     * Restore state machine from persisted state
     */
    async restoreState(taskId, persistedState) {
        const machine = await this.getStateMachine(taskId);
        // Restore the machine to the persisted state
        const restoredState = xstate_1.State.create(persistedState);
        machine.start(restoredState);
    }
    /**
     * Clean up machine instance
     */
    async cleanup(taskId) {
        const machine = this.machines.get(taskId);
        if (machine) {
            machine.stop();
            this.machines.delete(taskId);
        }
    }
}
exports.StateMachineService = StateMachineService;
// Export singleton instance
exports.stateMachineService = new StateMachineService();
//# sourceMappingURL=stateMachine.js.map