<?php
require_once 'db/config.php';
require_once 'lib/ErrorHandler.php';

register_error_handler();

session_start();

function validate_definition_json($json) {
    if (empty($json)) {
        http_response_code(422);
        throw new WorkflowRuleFailedException('Process definition JSON cannot be empty.');
    }
    $data = json_decode($json, true);
    if (json_last_error() !== JSON_ERROR_NONE) {
        http_response_code(422);
        throw new WorkflowRuleFailedException('Invalid JSON format in definition.');
    }

    $allowed_statuses = ['none', 'negative', 'in_progress', 'positive', 'active', 'processing', 'paused', 'completed', 'terminated'];

    if (isset($data['nodes'])) {
        foreach ($data['nodes'] as $node) {
            if (isset($node['ui_hints']['status']) && !in_array($node['ui_hints']['status'], $allowed_statuses)) {
                http_response_code(422);
                throw new WorkflowRuleFailedException('Invalid status in ui_hints. Allowed values are: ' . implode(', ', $allowed_statuses));
            }
        }
    }

    if (isset($data['transitions'])) {
        foreach ($data['transitions'] as $transition) {
            if (isset($transition['actions'])) {
                foreach ($transition['actions'] as $action) {
                    if ($action['type'] === 'start_process' && isset($action['process_name'])) {
                        http_response_code(422);
                        throw new WorkflowRuleFailedException('Use process_code instead of process_name in transition actions.');
                    }
                }
            }
        }
    }
    
    if (isset($data['eligibility_rules'])) {
        foreach ($data['eligibility_rules'] as $rule) {
            if ($rule['type'] === 'process_completed' && isset($rule['process_name'])) {
                http_response_code(422);
                throw new WorkflowRuleFailedException('Use process_code instead of process_name in eligibility_rules.');
            }
        }
    }

    if (!isset($data['start_node_id'])) {
        http_response_code(422);
        throw new WorkflowRuleFailedException('Process definition is missing start_node_id.');
    }

    $start_node_id = $data['start_node_id'];
    
    if (!isset($data['nodes']) || !is_array($data['nodes'])) {
        http_response_code(422);
        throw new WorkflowRuleFailedException('Process definition is missing a valid "nodes" object.');
    }

    if (!isset($data['nodes'][$start_node_id])) {
        http_response_code(422);
        throw new WorkflowRuleFailedException("start_node_id '{$start_node_id}' does not exist in nodes.");
    }
    
    if (!isset($data['transitions']) || !is_array($data['transitions'])) {
        http_response_code(422);
        throw new WorkflowRuleFailedException('Process definition is missing a valid "transitions" array.');
    }

    foreach ($data['transitions'] as $index => $transition) {
        if (!isset($transition['from']) || !isset($transition['to'])) {
            http_response_code(422);
            throw new WorkflowRuleFailedException("Transition at index {$index} is missing 'from' or 'to' property.");
        }
        if (!isset($data['nodes'][$transition['from']])) {
            http_response_code(422);
            throw new WorkflowRuleFailedException("Transition from an unknown node: '{$transition['from']}'.");
        }
        if (!isset($data['nodes'][$transition['to']])) {
            http_response_code(422);
            throw new WorkflowRuleFailedException("Transition to an unknown node: '{$transition['to']}'.");
        }
    }
}

try {
    if ($_SERVER['REQUEST_METHOD'] === 'POST') {
        $processId = $_POST['process_id'] ?? null;
        $name = $_POST['name'] ?? '';
        $definition_json = $_POST['definition_json'] ?? '';

        validate_definition_json($definition_json);

        // Generate a simple code from the name
        $code = strtolower(trim(preg_replace('/[^A-Za-z0-9-]+/', '-', $name)));

        if (empty($name)) {
            throw new WorkflowRuleFailedException('Process name is required.');
        }

        $pdo = db();
        $start_node = json_decode($definition_json, true)['start_node_id'] ?? null;

        if (empty($processId)) {
            // Create new process
            $sql = 'INSERT INTO process_definitions (name, code, definition_json, start_node_id, is_active, version, is_latest) VALUES (?, ?, ?, ?, 1, 1, 1)';
            $params = [$name, $code, $definition_json, $start_node];
            $message = 'Process created successfully.';
            $stmt = $pdo->prepare($sql);
            $stmt->execute($params);
        } else {
            // "Update" existing process by creating a new version
            $stmt_old = $pdo->prepare('SELECT code, version, sort_order, is_active FROM process_definitions WHERE id = ?');
            $stmt_old->execute([$processId]);
            $old = $stmt_old->fetch();
            
            if ($old) {
                $is_active = isset($_POST['is_active']) ? (int)$_POST['is_active'] : $old['is_active'];
                $new_version = $old['version'] + 1;
                $db_code = $old['code'];

                // Mark all previous versions as not latest
                $stmt_update = $pdo->prepare('UPDATE process_definitions SET is_latest = 0 WHERE code = ?');
                $stmt_update->execute([$db_code]);

                // Insert new version
                $sql = 'INSERT INTO process_definitions (name, code, definition_json, start_node_id, is_active, version, supersedes_definition_id, is_latest, sort_order) VALUES (?, ?, ?, ?, ?, ?, ?, 1, ?)';
                $params = [$name, $db_code, $definition_json, $start_node, $is_active, $new_version, $processId, $old['sort_order']];
                $stmt = $pdo->prepare($sql);
                $stmt->execute($params);
                $message = 'Process updated successfully (new version created).';
            } else {
                throw new WorkflowRuleFailedException('Process not found.');
            }
        }
        if (isset($_SERVER['HTTP_ACCEPT']) && strpos($_SERVER['HTTP_ACCEPT'], 'application/json') !== false) {
            header('Content-Type: application/json');
            echo json_encode(['message' => $message]);
        } else {
            $_SESSION['success_message'] = $message;
            header('Location: process_definitions.php');
            exit();
        }
    }
} catch (WorkflowRuleFailedException $e) {
    header('Content-Type: application/json');
    echo json_encode(['error' => $e->getMessage()]);
}
