/**
 * Workflow Schema Validation
 *
 * Defines types and validation for workflow definitions.
 * See pennyfarthing-dist/guides/workflow-schema.md for spec.
 */
/**
 * Validates a workflow definition object
 *
 * @param input - Raw workflow object (e.g., parsed from YAML)
 * @returns Validation result with parsed workflow or errors
 *
 * @example
 * ```typescript
 * const yaml = fs.readFileSync('workflow.yaml', 'utf-8');
 * const parsed = YAML.parse(yaml);
 * const result = validateWorkflow(parsed);
 *
 * if (result.valid) {
 *   console.log(`Workflow "${result.workflow.name}" is valid`);
 * } else {
 *   console.error('Validation errors:', result.errors);
 * }
 * ```
 */
export function validateWorkflow(input) {
    const errors = [];
    // Check input is an object
    if (!input || typeof input !== 'object') {
        return {
            valid: false,
            errors: [{ field: 'workflow', message: 'Input must be an object' }]
        };
    }
    const inputObj = input;
    // Check for root 'workflow' key
    if (!('workflow' in inputObj) || !inputObj.workflow || typeof inputObj.workflow !== 'object') {
        return {
            valid: false,
            errors: [{ field: 'workflow', message: 'Missing required root "workflow" key' }]
        };
    }
    const workflowObj = inputObj.workflow;
    // Validate workflow.name (required, string)
    if (!('name' in workflowObj) || workflowObj.name === undefined || workflowObj.name === null) {
        errors.push({ field: 'workflow.name', message: 'Name is required' });
    }
    else if (typeof workflowObj.name !== 'string') {
        errors.push({ field: 'workflow.name', message: 'Name must be a string' });
    }
    // Determine workflow type (default to 'phased' for backward compatibility)
    const workflowType = ('type' in workflowObj && workflowObj.type !== undefined)
        ? workflowObj.type
        : 'phased';
    // Validate type field if present
    if ('type' in workflowObj && workflowObj.type !== undefined) {
        if (workflowObj.type !== 'phased' && workflowObj.type !== 'stepped') {
            errors.push({ field: 'workflow.type', message: 'Type must be "phased" or "stepped"' });
        }
    }
    const isStepped = workflowType === 'stepped';
    const hasPhases = 'phases' in workflowObj && workflowObj.phases !== undefined;
    const hasSteps = 'steps' in workflowObj && workflowObj.steps !== undefined;
    // Validate mutual exclusivity: stepped workflows cannot have phases
    if (isStepped && hasPhases) {
        errors.push({ field: 'workflow.phases', message: 'Stepped workflows cannot have phases (mutually exclusive)' });
    }
    // Validate stepped workflow requirements
    if (isStepped) {
        // steps is required for stepped workflows
        if (!hasSteps) {
            errors.push({ field: 'workflow.steps', message: 'steps configuration is required for stepped workflows' });
        }
        else {
            // Validate steps object
            const stepsObj = workflowObj.steps;
            if (!stepsObj || typeof stepsObj !== 'object') {
                errors.push({ field: 'workflow.steps', message: 'Steps must be an object' });
            }
            else {
                // path is required and must be non-empty
                if (!('path' in stepsObj) || stepsObj.path === undefined || stepsObj.path === null) {
                    errors.push({ field: 'workflow.steps.path', message: 'Steps path is required' });
                }
                else if (typeof stepsObj.path !== 'string') {
                    errors.push({ field: 'workflow.steps.path', message: 'Steps path must be a string' });
                }
                else if (stepsObj.path.trim() === '') {
                    errors.push({ field: 'workflow.steps.path', message: 'Steps path cannot be empty' });
                }
                // pattern is required and must be non-empty
                if (!('pattern' in stepsObj) || stepsObj.pattern === undefined || stepsObj.pattern === null) {
                    errors.push({ field: 'workflow.steps.pattern', message: 'Steps pattern is required' });
                }
                else if (typeof stepsObj.pattern !== 'string') {
                    errors.push({ field: 'workflow.steps.pattern', message: 'Steps pattern must be a string' });
                }
                else if (stepsObj.pattern.trim() === '') {
                    errors.push({ field: 'workflow.steps.pattern', message: 'Steps pattern cannot be empty' });
                }
            }
        }
        // Validate modes (optional, but only valid for stepped)
        if ('modes' in workflowObj && workflowObj.modes !== undefined) {
            const modesObj = workflowObj.modes;
            if (!modesObj || typeof modesObj !== 'object') {
                errors.push({ field: 'workflow.modes', message: 'Modes must be an object' });
            }
            else {
                // default mode must be one of: create, validate, edit
                if ('default' in modesObj && modesObj.default !== undefined) {
                    if (modesObj.default !== 'create' && modesObj.default !== 'validate' && modesObj.default !== 'edit') {
                        errors.push({ field: 'workflow.modes.default', message: 'Modes default must be "create", "validate", or "edit"' });
                    }
                }
                // Mode paths must be strings if present
                for (const mode of ['create', 'validate', 'edit']) {
                    if (mode in modesObj && modesObj[mode] !== undefined && typeof modesObj[mode] !== 'string') {
                        errors.push({ field: `workflow.modes.${mode}`, message: `Modes ${mode} must be a string` });
                    }
                }
            }
        }
        // Validate stepped gates (optional)
        if ('gates' in workflowObj && workflowObj.gates !== undefined) {
            const gatesObj = workflowObj.gates;
            if (!gatesObj || typeof gatesObj !== 'object') {
                errors.push({ field: 'workflow.gates', message: 'Gates must be an object' });
            }
            else {
                // after_steps must be array of numbers if present
                if ('after_steps' in gatesObj && gatesObj.after_steps !== undefined) {
                    if (!Array.isArray(gatesObj.after_steps)) {
                        errors.push({ field: 'workflow.gates.after_steps', message: 'Gates after_steps must be an array' });
                    }
                    else {
                        const afterSteps = gatesObj.after_steps;
                        afterSteps.forEach((step, index) => {
                            if (typeof step !== 'number') {
                                errors.push({ field: `workflow.gates.after_steps[${index}]`, message: 'Gates after_steps values must be numbers' });
                            }
                        });
                    }
                }
                // gate_marker must be string if present
                if ('gate_marker' in gatesObj && gatesObj.gate_marker !== undefined) {
                    if (typeof gatesObj.gate_marker !== 'string') {
                        errors.push({ field: 'workflow.gates.gate_marker', message: 'Gates gate_marker must be a string' });
                    }
                }
            }
        }
        // Validate template (optional, string)
        if ('template' in workflowObj && workflowObj.template !== undefined) {
            if (typeof workflowObj.template !== 'string') {
                errors.push({ field: 'workflow.template', message: 'Template must be a string' });
            }
        }
        // Validate variables (optional, object) - no additional constraints
        // variables can be any object shape
    }
    else {
        // Phased workflow validation
        // modes is only valid for stepped workflows
        if ('modes' in workflowObj && workflowObj.modes !== undefined) {
            errors.push({ field: 'workflow.modes', message: 'modes configuration is only valid for stepped workflows' });
        }
    }
    // Validate workflow.phases (required for phased workflows)
    if (!isStepped) {
        if (!hasPhases) {
            errors.push({ field: 'workflow.phases', message: 'Phases is required' });
        }
        else if (!Array.isArray(workflowObj.phases)) {
            errors.push({ field: 'workflow.phases', message: 'Phases must be an array' });
        }
        else if (workflowObj.phases.length === 0) {
            errors.push({ field: 'workflow.phases', message: 'Workflow must have at least one phase' });
        }
        else {
            // Validate each phase
            const phases = workflowObj.phases;
            phases.forEach((phase, index) => {
                if (!phase || typeof phase !== 'object') {
                    errors.push({ field: `workflow.phases[${index}]`, message: 'Phase must be an object' });
                    return;
                }
                const phaseObj = phase;
                // Phase name (required)
                if (!('name' in phaseObj) || phaseObj.name === undefined || phaseObj.name === null) {
                    errors.push({ field: `workflow.phases[${index}].name`, message: 'Phase name is required' });
                }
                else if (typeof phaseObj.name !== 'string') {
                    errors.push({ field: `workflow.phases[${index}].name`, message: 'Phase name must be a string' });
                }
                // Phase agent (required)
                if (!('agent' in phaseObj) || phaseObj.agent === undefined || phaseObj.agent === null) {
                    errors.push({ field: `workflow.phases[${index}].agent`, message: 'Phase agent is required' });
                }
                else if (typeof phaseObj.agent !== 'string') {
                    errors.push({ field: `workflow.phases[${index}].agent`, message: 'Phase agent must be a string' });
                }
                // Phase gate (optional, but if present must have type)
                if ('gate' in phaseObj && phaseObj.gate !== undefined) {
                    if (!phaseObj.gate || typeof phaseObj.gate !== 'object') {
                        errors.push({ field: `workflow.phases[${index}].gate`, message: 'Gate must be an object' });
                    }
                    else {
                        const gateObj = phaseObj.gate;
                        if (!('type' in gateObj) || gateObj.type === undefined || gateObj.type === null) {
                            errors.push({ field: `workflow.phases[${index}].gate.type`, message: 'Gate type is required' });
                        }
                        else if (typeof gateObj.type !== 'string') {
                            errors.push({ field: `workflow.phases[${index}].gate.type`, message: 'Gate type must be a string' });
                        }
                    }
                }
                // Phase input (optional, array of strings)
                if ('input' in phaseObj && phaseObj.input !== undefined) {
                    if (!Array.isArray(phaseObj.input)) {
                        errors.push({ field: `workflow.phases[${index}].input`, message: 'Input must be an array' });
                    }
                }
                // Phase output (optional, array of strings)
                if ('output' in phaseObj && phaseObj.output !== undefined) {
                    if (!Array.isArray(phaseObj.output)) {
                        errors.push({ field: `workflow.phases[${index}].output`, message: 'Output must be an array' });
                    }
                }
            });
        }
    }
    // Validate triggers (optional)
    if ('triggers' in workflowObj && workflowObj.triggers !== undefined) {
        if (!workflowObj.triggers || typeof workflowObj.triggers !== 'object') {
            errors.push({ field: 'workflow.triggers', message: 'Triggers must be an object' });
        }
        else {
            const triggersObj = workflowObj.triggers;
            // tags (optional, array)
            if ('tags' in triggersObj && triggersObj.tags !== undefined) {
                if (!Array.isArray(triggersObj.tags)) {
                    errors.push({ field: 'workflow.triggers.tags', message: 'Tags must be an array' });
                }
            }
            // types (optional, array)
            if ('types' in triggersObj && triggersObj.types !== undefined) {
                if (!Array.isArray(triggersObj.types)) {
                    errors.push({ field: 'workflow.triggers.types', message: 'Types must be an array' });
                }
            }
            // points (optional, object with min/max)
            if ('points' in triggersObj && triggersObj.points !== undefined) {
                if (!triggersObj.points || typeof triggersObj.points !== 'object') {
                    errors.push({ field: 'workflow.triggers.points', message: 'Points must be an object' });
                }
                else {
                    const pointsObj = triggersObj.points;
                    // min (optional, number)
                    if ('min' in pointsObj && pointsObj.min !== undefined) {
                        if (typeof pointsObj.min !== 'number') {
                            errors.push({ field: 'workflow.triggers.points.min', message: 'Points min must be a number' });
                        }
                    }
                    // max (optional, number)
                    if ('max' in pointsObj && pointsObj.max !== undefined) {
                        if (typeof pointsObj.max !== 'number') {
                            errors.push({ field: 'workflow.triggers.points.max', message: 'Points max must be a number' });
                        }
                    }
                    // Validate min <= max if both present and valid numbers
                    if ('min' in pointsObj && 'max' in pointsObj &&
                        typeof pointsObj.min === 'number' && typeof pointsObj.max === 'number' &&
                        pointsObj.min > pointsObj.max) {
                        errors.push({ field: 'workflow.triggers.points', message: 'Points min cannot be greater than max' });
                    }
                }
            }
            // default (optional, boolean)
            if ('default' in triggersObj && triggersObj.default !== undefined) {
                if (typeof triggersObj.default !== 'boolean') {
                    errors.push({ field: 'workflow.triggers.default', message: 'Default must be a boolean' });
                }
            }
        }
    }
    // Validate permissions (optional, array of permission presets)
    if ('permissions' in workflowObj && workflowObj.permissions !== undefined) {
        if (!Array.isArray(workflowObj.permissions)) {
            errors.push({ field: 'workflow.permissions', message: 'Permissions must be an array' });
        }
        else {
            const permissions = workflowObj.permissions;
            permissions.forEach((permission, index) => {
                if (!permission || typeof permission !== 'object') {
                    errors.push({ field: `workflow.permissions[${index}]`, message: 'Permission must be an object' });
                    return;
                }
                const permObj = permission;
                // tool (required, string)
                if (!('tool' in permObj) || permObj.tool === undefined || permObj.tool === null) {
                    errors.push({ field: `workflow.permissions[${index}].tool`, message: 'Permission tool is required' });
                }
                else if (typeof permObj.tool !== 'string') {
                    errors.push({ field: `workflow.permissions[${index}].tool`, message: 'Permission tool must be a string' });
                }
                // scope (required, string)
                if (!('scope' in permObj) || permObj.scope === undefined || permObj.scope === null) {
                    errors.push({ field: `workflow.permissions[${index}].scope`, message: 'Permission scope is required' });
                }
                else if (typeof permObj.scope !== 'string') {
                    errors.push({ field: `workflow.permissions[${index}].scope`, message: 'Permission scope must be a string' });
                }
                // reason (required, string)
                if (!('reason' in permObj) || permObj.reason === undefined || permObj.reason === null) {
                    errors.push({ field: `workflow.permissions[${index}].reason`, message: 'Permission reason is required' });
                }
                else if (typeof permObj.reason !== 'string') {
                    errors.push({ field: `workflow.permissions[${index}].reason`, message: 'Permission reason must be a string' });
                }
            });
        }
    }
    // If there are errors, return invalid result
    if (errors.length > 0) {
        return { valid: false, errors };
    }
    // Build the validated workflow object
    const workflow = {
        name: workflowObj.name
    };
    // Set type (default to phased for backward compatibility)
    if ('type' in workflowObj && workflowObj.type !== undefined) {
        workflow.type = workflowObj.type;
    }
    // Determine if stepped for conditional field handling
    const isSteppedWorkflow = workflow.type === 'stepped';
    // Build phases array for phased workflows
    if (!isSteppedWorkflow && workflowObj.phases !== undefined) {
        workflow.phases = workflowObj.phases.map((phase) => {
            const result = {
                name: phase.name,
                agent: phase.agent
            };
            if (phase.input !== undefined) {
                result.input = phase.input;
            }
            if (phase.output !== undefined) {
                result.output = phase.output;
            }
            if (phase.gate !== undefined) {
                const gateObj = phase.gate;
                result.gate = {
                    type: gateObj.type
                };
                if (gateObj.condition !== undefined) {
                    result.gate.condition = gateObj.condition;
                }
            }
            return result;
        });
    }
    // Build stepped workflow fields
    if (isSteppedWorkflow) {
        // agent (optional for stepped workflows)
        if (workflowObj.agent !== undefined) {
            workflow.agent = workflowObj.agent;
        }
        // steps (required for stepped, already validated)
        if (workflowObj.steps !== undefined) {
            const stepsObj = workflowObj.steps;
            workflow.steps = {
                path: stepsObj.path,
                pattern: stepsObj.pattern
            };
        }
        // modes (optional)
        if (workflowObj.modes !== undefined) {
            const modesObj = workflowObj.modes;
            workflow.modes = {
                default: modesObj.default
            };
            if (modesObj.create !== undefined) {
                workflow.modes.create = modesObj.create;
            }
            if (modesObj.validate !== undefined) {
                workflow.modes.validate = modesObj.validate;
            }
            if (modesObj.edit !== undefined) {
                workflow.modes.edit = modesObj.edit;
            }
        }
        // variables (optional)
        if (workflowObj.variables !== undefined) {
            workflow.variables = workflowObj.variables;
        }
        // gates (optional, stepped workflow gates)
        if (workflowObj.gates !== undefined) {
            const gatesObj = workflowObj.gates;
            workflow.gates = {};
            if (gatesObj.after_steps !== undefined) {
                workflow.gates.after_steps = gatesObj.after_steps;
            }
            if (gatesObj.gate_marker !== undefined) {
                workflow.gates.gate_marker = gatesObj.gate_marker;
            }
        }
        // template (optional)
        if (workflowObj.template !== undefined) {
            workflow.template = workflowObj.template;
        }
    }
    if (workflowObj.description !== undefined) {
        workflow.description = workflowObj.description;
    }
    if (workflowObj.version !== undefined) {
        workflow.version = workflowObj.version;
    }
    if (workflowObj.triggers !== undefined) {
        const triggersObj = workflowObj.triggers;
        const triggers = {};
        if (triggersObj.tags !== undefined) {
            triggers.tags = triggersObj.tags;
        }
        if (triggersObj.types !== undefined) {
            triggers.types = triggersObj.types;
        }
        if (triggersObj.points !== undefined) {
            const pointsObj = triggersObj.points;
            triggers.points = {};
            if (pointsObj.min !== undefined) {
                triggers.points.min = pointsObj.min;
            }
            if (pointsObj.max !== undefined) {
                triggers.points.max = pointsObj.max;
            }
        }
        if (triggersObj.default !== undefined) {
            triggers.default = triggersObj.default;
        }
        workflow.triggers = triggers;
    }
    // Build permissions array if present
    if (workflowObj.permissions !== undefined) {
        const permissionsArr = workflowObj.permissions;
        workflow.permissions = permissionsArr.map((perm) => ({
            tool: perm.tool,
            scope: perm.scope,
            reason: perm.reason,
        }));
    }
    return { valid: true, workflow };
}
//# sourceMappingURL=workflow-schema.js.map