"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.attachmentFilenameSchema = exports.linkedQuerySchema = exports.epicLinkSchema = exports.epicListSchema = exports.epicSearchSchema = exports.updateEpicSchema = exports.createEpicSchema = exports.skillListSchema = exports.skillSearchSchema = exports.createSkillLinkSchema = exports.updateSkillSchema = exports.createSkillSchema = exports.fileListSchema = exports.fileSearchSchema = exports.listQuerySchema = exports.searchQuerySchema = exports.taskListSchema = exports.taskSearchSchema = exports.createTaskLinkSchema = exports.bulkDeleteSchema = exports.bulkPrioritySchema = exports.bulkMoveSchema = exports.reorderTaskSchema = exports.moveTaskSchema = exports.updateTaskSchema = exports.createTaskSchema = exports.noteListSchema = exports.noteSearchSchema = exports.createRelationSchema = exports.updateNoteSchema = exports.createNoteSchema = void 0;
exports.validateBody = validateBody;
exports.validateQuery = validateQuery;
const zod_1 = require("zod");
const defaults_1 = require("../../lib/defaults");
function validateBody(schema) {
    return (req, _res, next) => {
        req.body = schema.parse(req.body);
        next();
    };
}
function validateQuery(schema) {
    return (req, _res, next) => {
        req.validatedQuery = schema.parse(req.query);
        next();
    };
}
// ---------------------------------------------------------------------------
// Knowledge schemas
// ---------------------------------------------------------------------------
exports.createNoteSchema = zod_1.z.object({
    title: zod_1.z.string().min(1).max(defaults_1.MAX_TITLE_LEN),
    content: zod_1.z.string().max(defaults_1.MAX_NOTE_CONTENT_LEN),
    tags: zod_1.z.array(zod_1.z.string().max(defaults_1.MAX_TAG_LEN)).max(defaults_1.MAX_TAGS_COUNT).optional().default([]),
});
exports.updateNoteSchema = zod_1.z.object({
    title: zod_1.z.string().min(1).max(defaults_1.MAX_TITLE_LEN).optional(),
    content: zod_1.z.string().max(defaults_1.MAX_NOTE_CONTENT_LEN).optional(),
    tags: zod_1.z.array(zod_1.z.string().max(defaults_1.MAX_TAG_LEN)).max(defaults_1.MAX_TAGS_COUNT).optional(),
    version: zod_1.z.number().int().positive().optional(),
});
exports.createRelationSchema = zod_1.z.object({
    fromId: zod_1.z.string().min(1).max(defaults_1.MAX_TARGET_NODE_ID_LEN),
    toId: zod_1.z.string().min(1).max(defaults_1.MAX_TARGET_NODE_ID_LEN),
    kind: zod_1.z.string().min(1).max(defaults_1.MAX_LINK_KIND_LEN),
    targetGraph: zod_1.z.enum(['docs', 'code', 'files', 'tasks', 'skills']).optional(),
    projectId: zod_1.z.string().min(1).max(defaults_1.MAX_PROJECT_ID_LEN).optional(),
});
exports.noteSearchSchema = zod_1.z.object({
    q: zod_1.z.string().min(1).max(defaults_1.MAX_SEARCH_QUERY_LEN),
    topK: zod_1.z.coerce.number().int().positive().max(defaults_1.MAX_SEARCH_TOP_K).optional(),
    minScore: zod_1.z.coerce.number().min(0).max(1).optional(),
    searchMode: zod_1.z.enum(['hybrid', 'vector', 'keyword']).optional(),
    bfsDepth: zod_1.z.coerce.number().int().min(0).max(10).optional(),
    maxResults: zod_1.z.coerce.number().int().min(1).max(500).optional(),
    bfsDecay: zod_1.z.coerce.number().min(0).max(1).optional(),
});
exports.noteListSchema = zod_1.z.object({
    filter: zod_1.z.string().max(500).optional(),
    tag: zod_1.z.string().max(defaults_1.MAX_TAG_LEN).optional(),
    limit: zod_1.z.coerce.number().int().positive().max(1000).optional(),
    offset: zod_1.z.coerce.number().int().min(0).max(100_000).optional().default(0),
});
// ---------------------------------------------------------------------------
// Task schemas
// ---------------------------------------------------------------------------
exports.createTaskSchema = zod_1.z.object({
    title: zod_1.z.string().min(1).max(defaults_1.MAX_TITLE_LEN),
    description: zod_1.z.string().max(defaults_1.MAX_DESCRIPTION_LEN).default(''),
    status: zod_1.z.enum(['backlog', 'todo', 'in_progress', 'review', 'done', 'cancelled']).default('todo'),
    priority: zod_1.z.enum(['critical', 'high', 'medium', 'low']).default('medium'),
    tags: zod_1.z.array(zod_1.z.string().max(defaults_1.MAX_TAG_LEN)).max(defaults_1.MAX_TAGS_COUNT).optional().default([]),
    dueDate: zod_1.z.number().nullable().optional(),
    estimate: zod_1.z.number().nullable().optional(),
    assignee: zod_1.z.string().max(defaults_1.MAX_ASSIGNEE_LEN).nullable().optional(),
    order: zod_1.z.number().int().optional(),
});
exports.updateTaskSchema = zod_1.z.object({
    title: zod_1.z.string().min(1).max(defaults_1.MAX_TITLE_LEN).optional(),
    description: zod_1.z.string().max(defaults_1.MAX_DESCRIPTION_LEN).optional(),
    status: zod_1.z.enum(['backlog', 'todo', 'in_progress', 'review', 'done', 'cancelled']).optional(),
    priority: zod_1.z.enum(['critical', 'high', 'medium', 'low']).optional(),
    tags: zod_1.z.array(zod_1.z.string().max(defaults_1.MAX_TAG_LEN)).max(defaults_1.MAX_TAGS_COUNT).optional(),
    order: zod_1.z.number().int().optional(),
    dueDate: zod_1.z.number().nullable().optional(),
    estimate: zod_1.z.number().nullable().optional(),
    assignee: zod_1.z.string().max(defaults_1.MAX_ASSIGNEE_LEN).nullable().optional(),
    version: zod_1.z.number().int().positive().optional(),
});
exports.moveTaskSchema = zod_1.z.object({
    status: zod_1.z.enum(['backlog', 'todo', 'in_progress', 'review', 'done', 'cancelled']),
    version: zod_1.z.number().int().positive().optional(),
    order: zod_1.z.number().int().min(0).optional(),
});
exports.reorderTaskSchema = zod_1.z.object({
    order: zod_1.z.number().int(),
    status: zod_1.z.enum(['backlog', 'todo', 'in_progress', 'review', 'done', 'cancelled']).optional(),
});
exports.bulkMoveSchema = zod_1.z.object({
    taskIds: zod_1.z.array(zod_1.z.string().min(1).max(500)).min(1).max(100),
    status: zod_1.z.enum(['backlog', 'todo', 'in_progress', 'review', 'done', 'cancelled']),
});
exports.bulkPrioritySchema = zod_1.z.object({
    taskIds: zod_1.z.array(zod_1.z.string().min(1).max(500)).min(1).max(100),
    priority: zod_1.z.enum(['critical', 'high', 'medium', 'low']),
});
exports.bulkDeleteSchema = zod_1.z.object({
    taskIds: zod_1.z.array(zod_1.z.string().min(1).max(500)).min(1).max(100),
});
exports.createTaskLinkSchema = zod_1.z.object({
    fromId: zod_1.z.string().min(1).max(defaults_1.MAX_TARGET_NODE_ID_LEN),
    toId: zod_1.z.string().min(1).max(defaults_1.MAX_TARGET_NODE_ID_LEN),
    kind: zod_1.z.string().min(1).max(defaults_1.MAX_LINK_KIND_LEN),
    targetGraph: zod_1.z.enum(['docs', 'code', 'files', 'knowledge', 'skills']).optional(),
    projectId: zod_1.z.string().min(1).max(defaults_1.MAX_PROJECT_ID_LEN).optional(),
});
exports.taskSearchSchema = zod_1.z.object({
    q: zod_1.z.string().min(1).max(defaults_1.MAX_SEARCH_QUERY_LEN),
    topK: zod_1.z.coerce.number().int().positive().max(defaults_1.MAX_SEARCH_TOP_K).optional(),
    minScore: zod_1.z.coerce.number().min(0).max(1).optional(),
    searchMode: zod_1.z.enum(['hybrid', 'vector', 'keyword']).optional(),
    bfsDepth: zod_1.z.coerce.number().int().min(0).max(10).optional(),
    maxResults: zod_1.z.coerce.number().int().min(1).max(500).optional(),
    bfsDecay: zod_1.z.coerce.number().min(0).max(1).optional(),
});
exports.taskListSchema = zod_1.z.object({
    status: zod_1.z.enum(['backlog', 'todo', 'in_progress', 'review', 'done', 'cancelled']).optional(),
    priority: zod_1.z.enum(['critical', 'high', 'medium', 'low']).optional(),
    tag: zod_1.z.string().max(defaults_1.MAX_TAG_LEN).optional(),
    filter: zod_1.z.string().max(500).optional(),
    assignee: zod_1.z.string().max(defaults_1.MAX_ASSIGNEE_LEN).optional(),
    limit: zod_1.z.coerce.number().int().positive().max(1000).optional(),
    offset: zod_1.z.coerce.number().int().min(0).max(100_000).optional().default(0),
});
// ---------------------------------------------------------------------------
// Search schemas (docs, code, files)
// ---------------------------------------------------------------------------
exports.searchQuerySchema = zod_1.z.object({
    q: zod_1.z.string().min(1).max(defaults_1.MAX_SEARCH_QUERY_LEN),
    topK: zod_1.z.coerce.number().int().positive().max(defaults_1.MAX_SEARCH_TOP_K).optional(),
    minScore: zod_1.z.coerce.number().min(0).max(1).optional(),
    searchMode: zod_1.z.enum(['hybrid', 'vector', 'keyword']).optional(),
    bfsDepth: zod_1.z.coerce.number().int().min(0).max(10).optional(),
    maxResults: zod_1.z.coerce.number().int().min(1).max(500).optional(),
    bfsDecay: zod_1.z.coerce.number().min(0).max(1).optional(),
    includeBody: zod_1.z.coerce.boolean().optional(),
});
exports.listQuerySchema = zod_1.z.object({
    filter: zod_1.z.string().max(500).optional(),
    limit: zod_1.z.coerce.number().int().positive().max(1000).optional(),
    offset: zod_1.z.coerce.number().int().min(0).max(100_000).optional().default(0),
});
// ---------------------------------------------------------------------------
// File index schemas
// ---------------------------------------------------------------------------
exports.fileSearchSchema = zod_1.z.object({
    q: zod_1.z.string().min(1).max(defaults_1.MAX_SEARCH_QUERY_LEN),
    topK: zod_1.z.coerce.number().int().positive().max(defaults_1.MAX_SEARCH_TOP_K).optional(),
    minScore: zod_1.z.coerce.number().min(0).max(1).optional(),
});
exports.fileListSchema = zod_1.z.object({
    directory: zod_1.z.string().max(4096).optional(),
    extension: zod_1.z.string().max(100).optional(),
    language: zod_1.z.string().max(100).optional(),
    filter: zod_1.z.string().max(500).optional(),
    limit: zod_1.z.coerce.number().int().positive().max(1000).optional().default(50),
    offset: zod_1.z.coerce.number().int().min(0).max(100_000).optional().default(0),
});
// ---------------------------------------------------------------------------
// Skill schemas
// ---------------------------------------------------------------------------
exports.createSkillSchema = zod_1.z.object({
    title: zod_1.z.string().min(1).max(defaults_1.MAX_TITLE_LEN),
    description: zod_1.z.string().max(defaults_1.MAX_DESCRIPTION_LEN).default(''),
    steps: zod_1.z.array(zod_1.z.string().max(defaults_1.MAX_SKILL_STEP_LEN)).max(defaults_1.MAX_SKILL_STEPS_COUNT).optional().default([]),
    triggers: zod_1.z.array(zod_1.z.string().max(defaults_1.MAX_SKILL_TRIGGER_LEN)).max(defaults_1.MAX_SKILL_TRIGGERS_COUNT).optional().default([]),
    inputHints: zod_1.z.array(zod_1.z.string().max(defaults_1.MAX_SKILL_TRIGGER_LEN)).max(defaults_1.MAX_SKILL_TRIGGERS_COUNT).optional().default([]),
    filePatterns: zod_1.z.array(zod_1.z.string().max(defaults_1.MAX_SKILL_TRIGGER_LEN)).max(defaults_1.MAX_SKILL_TRIGGERS_COUNT).optional().default([]),
    tags: zod_1.z.array(zod_1.z.string().max(defaults_1.MAX_TAG_LEN)).max(defaults_1.MAX_TAGS_COUNT).optional().default([]),
    source: zod_1.z.enum(['user', 'learned']).default('user'),
    confidence: zod_1.z.number().min(0).max(1).default(1),
});
exports.updateSkillSchema = zod_1.z.object({
    title: zod_1.z.string().min(1).max(defaults_1.MAX_TITLE_LEN).optional(),
    description: zod_1.z.string().max(defaults_1.MAX_DESCRIPTION_LEN).optional(),
    steps: zod_1.z.array(zod_1.z.string().max(defaults_1.MAX_SKILL_STEP_LEN)).max(defaults_1.MAX_SKILL_STEPS_COUNT).optional(),
    triggers: zod_1.z.array(zod_1.z.string().max(defaults_1.MAX_SKILL_TRIGGER_LEN)).max(defaults_1.MAX_SKILL_TRIGGERS_COUNT).optional(),
    inputHints: zod_1.z.array(zod_1.z.string().max(defaults_1.MAX_SKILL_TRIGGER_LEN)).max(defaults_1.MAX_SKILL_TRIGGERS_COUNT).optional(),
    filePatterns: zod_1.z.array(zod_1.z.string().max(defaults_1.MAX_SKILL_TRIGGER_LEN)).max(defaults_1.MAX_SKILL_TRIGGERS_COUNT).optional(),
    tags: zod_1.z.array(zod_1.z.string().max(defaults_1.MAX_TAG_LEN)).max(defaults_1.MAX_TAGS_COUNT).optional(),
    source: zod_1.z.enum(['user', 'learned']).optional(),
    confidence: zod_1.z.number().min(0).max(1).optional(),
    version: zod_1.z.number().int().positive().optional(),
});
exports.createSkillLinkSchema = zod_1.z.object({
    fromId: zod_1.z.string().min(1).max(defaults_1.MAX_TARGET_NODE_ID_LEN),
    toId: zod_1.z.string().min(1).max(defaults_1.MAX_TARGET_NODE_ID_LEN),
    kind: zod_1.z.string().min(1).max(defaults_1.MAX_LINK_KIND_LEN),
    targetGraph: zod_1.z.enum(['docs', 'code', 'files', 'knowledge', 'tasks']).optional(),
    projectId: zod_1.z.string().min(1).max(defaults_1.MAX_PROJECT_ID_LEN).optional(),
});
exports.skillSearchSchema = zod_1.z.object({
    q: zod_1.z.string().min(1).max(defaults_1.MAX_SEARCH_QUERY_LEN),
    topK: zod_1.z.coerce.number().int().positive().max(defaults_1.MAX_SEARCH_TOP_K).optional(),
    minScore: zod_1.z.coerce.number().min(0).max(1).optional(),
    searchMode: zod_1.z.enum(['hybrid', 'vector', 'keyword']).optional(),
    bfsDepth: zod_1.z.coerce.number().int().min(0).max(10).optional(),
    maxResults: zod_1.z.coerce.number().int().min(1).max(500).optional(),
    bfsDecay: zod_1.z.coerce.number().min(0).max(1).optional(),
});
exports.skillListSchema = zod_1.z.object({
    source: zod_1.z.enum(['user', 'learned']).optional(),
    tag: zod_1.z.string().max(defaults_1.MAX_TAG_LEN).optional(),
    filter: zod_1.z.string().max(500).optional(),
    limit: zod_1.z.coerce.number().int().positive().max(1000).optional(),
    offset: zod_1.z.coerce.number().int().min(0).max(100_000).optional().default(0),
});
// ---------------------------------------------------------------------------
// Epic schemas
// ---------------------------------------------------------------------------
exports.createEpicSchema = zod_1.z.object({
    title: zod_1.z.string().min(1).max(defaults_1.MAX_TITLE_LEN),
    description: zod_1.z.string().max(defaults_1.MAX_DESCRIPTION_LEN).default(''),
    status: zod_1.z.enum(['open', 'in_progress', 'done', 'cancelled']).default('open'),
    priority: zod_1.z.enum(['critical', 'high', 'medium', 'low']).default('medium'),
    tags: zod_1.z.array(zod_1.z.string().max(defaults_1.MAX_TAG_LEN)).max(defaults_1.MAX_TAGS_COUNT).optional().default([]),
});
exports.updateEpicSchema = zod_1.z.object({
    title: zod_1.z.string().min(1).max(defaults_1.MAX_TITLE_LEN).optional(),
    description: zod_1.z.string().max(defaults_1.MAX_DESCRIPTION_LEN).optional(),
    status: zod_1.z.enum(['open', 'in_progress', 'done', 'cancelled']).optional(),
    priority: zod_1.z.enum(['critical', 'high', 'medium', 'low']).optional(),
    tags: zod_1.z.array(zod_1.z.string().max(defaults_1.MAX_TAG_LEN)).max(defaults_1.MAX_TAGS_COUNT).optional(),
    version: zod_1.z.number().int().positive().optional(),
});
exports.epicSearchSchema = zod_1.z.object({
    q: zod_1.z.string().min(1).max(defaults_1.MAX_SEARCH_QUERY_LEN),
    topK: zod_1.z.coerce.number().int().positive().max(defaults_1.MAX_SEARCH_TOP_K).optional(),
    minScore: zod_1.z.coerce.number().min(0).max(1).optional(),
    searchMode: zod_1.z.enum(['hybrid', 'vector', 'keyword']).optional(),
});
exports.epicListSchema = zod_1.z.object({
    status: zod_1.z.enum(['open', 'in_progress', 'done', 'cancelled']).optional(),
    priority: zod_1.z.enum(['critical', 'high', 'medium', 'low']).optional(),
    tag: zod_1.z.string().max(defaults_1.MAX_TAG_LEN).optional(),
    filter: zod_1.z.string().max(500).optional(),
    limit: zod_1.z.coerce.number().int().positive().max(1000).optional(),
    offset: zod_1.z.coerce.number().int().min(0).max(100_000).optional().default(0),
});
exports.epicLinkSchema = zod_1.z.object({
    taskId: zod_1.z.string().min(1).max(500),
});
// ---------------------------------------------------------------------------
// Linked query schema (cross-graph reverse lookup)
// ---------------------------------------------------------------------------
exports.linkedQuerySchema = zod_1.z.object({
    targetGraph: zod_1.z.enum(['docs', 'code', 'files', 'knowledge', 'tasks', 'skills']),
    targetNodeId: zod_1.z.string().min(1).max(defaults_1.MAX_TARGET_NODE_ID_LEN),
    kind: zod_1.z.string().max(defaults_1.MAX_LINK_KIND_LEN).optional(),
    projectId: zod_1.z.string().max(defaults_1.MAX_PROJECT_ID_LEN).optional(),
});
// ---------------------------------------------------------------------------
// Attachment schemas
// ---------------------------------------------------------------------------
/** Validates an attachment filename (path param). No path separators, no .., no dangerous chars. */
exports.attachmentFilenameSchema = zod_1.z.string()
    .min(1)
    .max(defaults_1.MAX_ATTACHMENT_FILENAME_LEN)
    .refine(s => !/[/\\]/.test(s), 'Filename must not contain path separators')
    .refine(s => !s.includes('..'), 'Filename must not contain ..')
    .refine(s => !s.includes('\0'), 'Filename must not contain null bytes')
    .refine(s => !/[\x00-\x1f\x7f"<>|?*]/.test(s), 'Filename contains invalid characters');
