"use strict";
var __extends = (this && this.__extends) || (function () {
    var extendStatics = function (d, b) {
        extendStatics = Object.setPrototypeOf ||
            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
            function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
        return extendStatics(d, b);
    };
    return function (d, b) {
        if (typeof b !== "function" && b !== null)
            throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var __assign = (this && this.__assign) || function () {
    __assign = Object.assign || function(t) {
        for (var s, i = 1, n = arguments.length; i < n; i++) {
            s = arguments[i];
            for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
                t[p] = s[p];
        }
        return t;
    };
    return __assign.apply(this, arguments);
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __generator = (this && this.__generator) || function (thisArg, body) {
    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
    return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
    function verb(n) { return function (v) { return step([n, v]); }; }
    function step(op) {
        if (f) throw new TypeError("Generator is already executing.");
        while (g && (g = 0, op[0] && (_ = 0)), _) try {
            if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
            if (y = 0, t) op = [op[0] & 2, t.value];
            switch (op[0]) {
                case 0: case 1: t = op; break;
                case 4: _.label++; return { value: op[1], done: false };
                case 5: _.label++; y = op[1]; op = [0]; continue;
                case 7: op = _.ops.pop(); _.trys.pop(); continue;
                default:
                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
                    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
                    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
                    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
                    if (t[2]) _.ops.pop();
                    _.trys.pop(); continue;
            }
            op = body.call(thisArg, _);
        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
        if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
    }
};
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
    if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
        if (ar || !(i in from)) {
            if (!ar) ar = Array.prototype.slice.call(from, 0, i);
            ar[i] = from[i];
        }
    }
    return to.concat(ar || Array.prototype.slice.call(from));
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.BoardPostAutomationLockedError = exports.boardPostPayloadSchema = exports.boardPostRequestExecutionModeSchema = exports.boardPostRequestSchema = exports.BOARD_POST_REQUESTS_TABLE = exports.BOARD_POSTS_TABLE = void 0;
exports.buildBoardPostPlanNote = buildBoardPostPlanNote;
exports.resolveSequencedPlanWorkId = resolveSequencedPlanWorkId;
exports.ensureBoardPostsTable = ensureBoardPostsTable;
exports.listBoardPosts = listBoardPosts;
exports.getBoardPost = getBoardPost;
exports.createBoardPost = createBoardPost;
exports.receiveBoardPostAutomation = receiveBoardPostAutomation;
exports.progressBoardPostAutomationByPlanResult = progressBoardPostAutomationByPlanResult;
exports.updateBoardPost = updateBoardPost;
exports.deleteBoardPost = deleteBoardPost;
var zod_1 = require("zod");
var client_js_1 = require("../db/client.js");
var plan_service_js_1 = require("./plan-service.js");
var automation_type_config_service_js_1 = require("./automation-type-config-service.js");
var automation_context_service_js_1 = require("./automation-context-service.js");
exports.BOARD_POSTS_TABLE = 'board_posts';
exports.BOARD_POST_REQUESTS_TABLE = 'board_post_requests';
var boardRequestExecutionModes = ['all_at_once', 'after_previous_finished', 'after_previous_success'];
var boardRequestWorkflowStates = ['pending', 'waiting', 'registered', 'completed', 'failed', 'blocked'];
var planFailureWorkerStatuses = new Set(['브랜치실패', '자동작업실패', 'release반영실패', 'main반영실패', '작업취소']);
var planRunningStatuses = new Set(['등록', '작업중', '작업완료', '릴리즈완료']);
var planRunningWorkerStatuses = new Set([
    '대기',
    '브랜치생성중',
    '브랜치준비',
    '자동작업중',
    'release반영대기',
    'release반영중',
    'release반영완료',
    'main반영대기',
    'main반영중',
    'main반영완료',
]);
exports.boardPostRequestSchema = zod_1.z.object({
    title: zod_1.z.string().trim().min(1).max(200),
    content: zod_1.z.string().min(1).max(200000),
});
exports.boardPostRequestExecutionModeSchema = zod_1.z.enum(boardRequestExecutionModes);
exports.boardPostPayloadSchema = zod_1.z.object({
    title: zod_1.z.string().trim().min(1).max(200),
    content: zod_1.z.string().max(200000).default(''),
    attachments: zod_1.z.array(zod_1.z.object({
        id: zod_1.z.string().trim().min(1).max(120),
        name: zod_1.z.string().trim().min(1).max(255),
        path: zod_1.z.string().trim().min(1).max(2000),
        publicUrl: zod_1.z.string().trim().min(1).max(2000),
        size: zod_1.z.coerce.number().int().min(0).max(10 * 1024 * 1024),
        mimeType: zod_1.z.string().trim().min(1).max(200),
    })).max(20).default([]),
    automationType: zod_1.z.preprocess(function (value) { return value; }, plan_service_js_1.planAutomationTypeSchema.default('none')),
    automationContextIds: zod_1.z.array(zod_1.z.string().trim().min(1).max(160)).max(20).optional().default([]),
    requestExecutionMode: exports.boardPostRequestExecutionModeSchema.default('all_at_once'),
    requestItems: zod_1.z.array(exports.boardPostRequestSchema).max(20).optional().default([]),
});
var BoardPostAutomationLockedError = /** @class */ (function (_super) {
    __extends(BoardPostAutomationLockedError, _super);
    function BoardPostAutomationLockedError(action) {
        var _this = _super.call(this, action === 'delete'
            ? '자동화 접수된 작업메모는 삭제할 수 없습니다.'
            : '자동화 접수된 작업메모는 수정할 수 없습니다.') || this;
        _this.name = 'BoardPostAutomationLockedError';
        return _this;
    }
    return BoardPostAutomationLockedError;
}(Error));
exports.BoardPostAutomationLockedError = BoardPostAutomationLockedError;
var MAX_SEQUENCED_PLAN_WORK_ID = 999;
var PLAN_WORK_ID_MAX_LENGTH = 120;
function createPreview(content) {
    var normalized = content
        .replace(/```[\s\S]*?```/g, ' ')
        .replace(/!\[[^\]]*\]\([^)]+\)/g, ' ')
        .replace(/\[([^\]]+)\]\(([^)]+)\)/g, '$1')
        .replace(/[#>*_`~-]/g, ' ')
        .replace(/\s+/g, ' ')
        .trim();
    return normalized.length > 140 ? "".concat(normalized.slice(0, 137).trimEnd(), "...") : normalized;
}
function normalizeBoardPostRequestItems(requestItems, fallbackTitle, fallbackContent) {
    if (requestItems.length > 0) {
        return requestItems.map(function (item) { return ({
            title: item.title.trim(),
            content: item.content.trim(),
        }); });
    }
    return [
        {
            title: fallbackTitle.trim() || '요청 1',
            content: fallbackContent.trim(),
        },
    ];
}
function resolveBoardRequestWorkflowState(value) {
    return boardRequestWorkflowStates.includes(value)
        ? value
        : 'pending';
}
function resolveBoardRequestExecutionMode(value) {
    return boardRequestExecutionModes.includes(value)
        ? value
        : 'all_at_once';
}
function resolveBoardRequestStatus(args) {
    var workflowState = args.workflowState, planStatus = args.planStatus, workerStatus = args.workerStatus, lastError = args.lastError;
    if (workflowState === 'blocked') {
        return { status: 'blocked', statusLabel: '차단' };
    }
    if (planStatus === '완료' || workflowState === 'completed') {
        return { status: 'completed', statusLabel: '완료' };
    }
    if (lastError || (workerStatus && planFailureWorkerStatuses.has(workerStatus)) || workflowState === 'failed') {
        return { status: 'failed', statusLabel: '실패' };
    }
    if ((planStatus && planRunningStatuses.has(planStatus))
        || (workerStatus && planRunningWorkerStatuses.has(workerStatus))) {
        return {
            status: planStatus === '등록' && workerStatus === '대기' ? 'queued' : 'in_progress',
            statusLabel: planStatus === '등록' && workerStatus === '대기' ? '대기열' : '진행중',
        };
    }
    if (workflowState === 'waiting') {
        return { status: 'waiting', statusLabel: '선행 대기' };
    }
    if (workflowState === 'registered' || args.planStatus || args.workerStatus) {
        return { status: 'queued', statusLabel: '대기열' };
    }
    return { status: 'pending', statusLabel: '미접수' };
}
function buildBoardAttachmentSection(attachments) {
    var lines = attachments
        .map(function (attachment) {
        var label = attachment.name.trim() || attachment.path.trim().split('/').pop() || '첨부 파일';
        var path = attachment.path.trim();
        if (!path) {
            return null;
        }
        return "- ".concat(label, ": ").concat(path);
    })
        .filter(function (line) { return Boolean(line); });
    if (lines.length === 0) {
        return [];
    }
    return __spreadArray(['## 첨부 파일'], lines, true);
}
function buildBoardPostPlanNote(title_1, content_1) {
    return __awaiter(this, arguments, void 0, function (title, content, attachments, automationType, automationContextIds, availableContexts, requestItem, sequenceInfo) {
        var note, commonContent, requestTitle, requestContent, lines, contextSection, contextBody, attachmentSection;
        var _a;
        if (attachments === void 0) { attachments = []; }
        return __generator(this, function (_b) {
            switch (_b.label) {
                case 0: return [4 /*yield*/, (0, automation_context_service_js_1.buildAutomationNoteSections)({
                        title: title.trim(),
                        sourceLabel: 'board_posts 자동화 접수',
                        requestContent: requestItem ? requestItem.content.trim() : content.trim(),
                        attachments: attachments.length ? buildBoardAttachmentSection(attachments).slice(1) : [],
                        automationType: automationType,
                        availableContexts: availableContexts,
                        selectedContextIds: automationContextIds,
                    })];
                case 1:
                    note = _b.sent();
                    if (!requestItem) {
                        return [2 /*return*/, note];
                    }
                    commonContent = content.trim();
                    requestTitle = requestItem.title.trim();
                    requestContent = requestItem.content.trim();
                    lines = [
                        '# 자동화 작업메모',
                        '',
                        "- \uAC8C\uC2DC\uD310 \uC81C\uBAA9: ".concat(title.trim()),
                        '- 메모 출처: board_posts 자동화 접수',
                        "- \uD558\uC704 \uC694\uCCAD: ".concat(requestTitle),
                    ];
                    if (sequenceInfo) {
                        lines.push("- \uC694\uCCAD \uC21C\uC11C: ".concat(sequenceInfo.index, "/").concat(sequenceInfo.total));
                    }
                    if (automationType === null || automationType === void 0 ? void 0 : automationType.name) {
                        lines.push("- \uC120\uD0DD \uC790\uB3D9\uD654 \uC720\uD615: ".concat(automationType.name));
                    }
                    lines.push('- 자동화 처리 원칙: 아래에서 선택된 자동화 Context만 우선 참조합니다.', '', '## 자동화 Context');
                    contextSection = (_a = note.split('## 자동화 Context\n')[1]) !== null && _a !== void 0 ? _a : '선택된 자동화 Context 없음\n\n## 요청 본문\n';
                    contextBody = contextSection.split('\n\n## 요청 본문\n')[0];
                    lines.push(contextBody.trim() || '선택된 자동화 Context 없음');
                    if (commonContent) {
                        lines.push('', '## 공통 메모', commonContent);
                    }
                    lines.push('', '## 요청 본문', requestContent);
                    attachmentSection = buildBoardAttachmentSection(attachments);
                    if (attachmentSection.length > 0) {
                        lines.push.apply(lines, __spreadArray([''], attachmentSection, false));
                    }
                    return [2 /*return*/, lines.join('\n')];
            }
        });
    });
}
function buildSequencedPlanWorkId(baseWorkId, sequence, suffixLabel) {
    var normalizedBaseWorkId = (0, plan_service_js_1.normalizePlanWorkId)(baseWorkId);
    var normalizedSuffixLabel = String(suffixLabel !== null && suffixLabel !== void 0 ? suffixLabel : '').trim().replace(/^-+|-+$/g, '');
    var suffix = normalizedSuffixLabel ? "-".concat(normalizedSuffixLabel, "-").concat(sequence) : "-".concat(sequence);
    var maxBaseLength = Math.max(1, PLAN_WORK_ID_MAX_LENGTH - suffix.length);
    var trimmedBaseWorkId = normalizedBaseWorkId.slice(0, maxBaseLength).trimEnd() || '작업ID';
    return "".concat(trimmedBaseWorkId).concat(suffix);
}
function resolveSequencedPlanWorkId(baseWorkId, existingWorkIds, suffixLabel) {
    var existingWorkIdSet = new Set(Array.from(existingWorkIds, function (value) { return String(value !== null && value !== void 0 ? value : '').trim(); }).filter(Boolean));
    for (var sequence = 1; sequence <= MAX_SEQUENCED_PLAN_WORK_ID; sequence += 1) {
        var candidate = buildSequencedPlanWorkId(baseWorkId, sequence, suffixLabel);
        if (!existingWorkIdSet.has(candidate)) {
            return candidate;
        }
    }
    throw new Error("\uC790\uB3D9\uD654 \uC811\uC218 ID suffix\uB97C \uB354 \uC774\uC0C1 \uC0DD\uC131\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. (".concat(MAX_SEQUENCED_PLAN_WORK_ID, "\uAC1C \uCD08\uACFC)"));
}
function resolveInsertedId(result) {
    if (typeof result === 'number' && Number.isInteger(result) && result > 0) {
        return result;
    }
    if (Array.isArray(result)) {
        var first = result[0];
        if (typeof first === 'number' && Number.isInteger(first) && first > 0) {
            return first;
        }
        if (first && typeof first === 'object' && 'id' in first) {
            var id = Number(first.id);
            return Number.isInteger(id) && id > 0 ? id : null;
        }
    }
    if (result && typeof result === 'object' && 'id' in result) {
        var id = Number(result.id);
        return Number.isInteger(id) && id > 0 ? id : null;
    }
    return null;
}
function supportsReturning() {
    var _a;
    var clientName = String((_a = client_js_1.db.client.config.client) !== null && _a !== void 0 ? _a : '').toLowerCase();
    return ['pg', 'postgres', 'postgresql', 'sqlite3', 'better-sqlite3', 'oracledb', 'mssql'].includes(clientName);
}
function isDuplicateSchemaError(error, codes, patterns) {
    var candidate = error;
    var code = typeof (candidate === null || candidate === void 0 ? void 0 : candidate.code) === 'string' ? candidate.code : '';
    var message = typeof (candidate === null || candidate === void 0 ? void 0 : candidate.message) === 'string' ? candidate.message : '';
    return codes.includes(code) || patterns.some(function (pattern) { return pattern.test(message); });
}
function isDuplicateTableError(error) {
    return isDuplicateSchemaError(error, ['42P07'], [/already exists/i]);
}
function isDuplicateColumnError(error) {
    return isDuplicateSchemaError(error, ['42701'], [/already exists/i, /duplicate column/i]);
}
function ensureBoardPostRequestsTable() {
    return __awaiter(this, void 0, void 0, function () {
        var hasTable, error_1, requiredColumns, _loop_1, _i, requiredColumns_1, _a, columnName, createColumn;
        return __generator(this, function (_b) {
            switch (_b.label) {
                case 0: return [4 /*yield*/, client_js_1.db.schema.hasTable(exports.BOARD_POST_REQUESTS_TABLE)];
                case 1:
                    hasTable = _b.sent();
                    if (!!hasTable) return [3 /*break*/, 5];
                    _b.label = 2;
                case 2:
                    _b.trys.push([2, 4, , 5]);
                    return [4 /*yield*/, client_js_1.db.schema.createTable(exports.BOARD_POST_REQUESTS_TABLE, function (table) {
                            table.increments('id').primary();
                            table.integer('board_post_id').notNullable().index();
                            table.integer('sequence_no').notNullable().defaultTo(1);
                            table.string('title', 200).notNullable();
                            table.text('content').notNullable();
                            table.integer('plan_item_id').nullable().index();
                            table.timestamp('automation_received_at', { useTz: true }).nullable();
                            table.string('workflow_state', 40).notNullable().defaultTo('pending');
                            table.timestamp('created_at', { useTz: true }).notNullable().defaultTo(client_js_1.db.fn.now());
                            table.timestamp('updated_at', { useTz: true }).notNullable().defaultTo(client_js_1.db.fn.now());
                        })];
                case 3:
                    _b.sent();
                    return [3 /*break*/, 5];
                case 4:
                    error_1 = _b.sent();
                    if (!isDuplicateTableError(error_1)) {
                        throw error_1;
                    }
                    return [3 /*break*/, 5];
                case 5:
                    requiredColumns = [
                        ['board_post_id', function (table) { return table.integer('board_post_id').notNullable().index(); }],
                        ['sequence_no', function (table) { return table.integer('sequence_no').notNullable().defaultTo(1); }],
                        ['title', function (table) { return table.string('title', 200).notNullable().defaultTo('요청 1'); }],
                        ['content', function (table) { return table.text('content').notNullable().defaultTo(''); }],
                        ['plan_item_id', function (table) { return table.integer('plan_item_id').nullable().index(); }],
                        ['automation_received_at', function (table) { return table.timestamp('automation_received_at', { useTz: true }).nullable(); }],
                        ['workflow_state', function (table) { return table.string('workflow_state', 40).notNullable().defaultTo('pending'); }],
                        ['created_at', function (table) { return table.timestamp('created_at', { useTz: true }).notNullable().defaultTo(client_js_1.db.fn.now()); }],
                        ['updated_at', function (table) { return table.timestamp('updated_at', { useTz: true }).notNullable().defaultTo(client_js_1.db.fn.now()); }],
                    ];
                    _loop_1 = function (columnName, createColumn) {
                        var hasColumn, error_2;
                        return __generator(this, function (_c) {
                            switch (_c.label) {
                                case 0: return [4 /*yield*/, client_js_1.db.schema.hasColumn(exports.BOARD_POST_REQUESTS_TABLE, columnName)];
                                case 1:
                                    hasColumn = _c.sent();
                                    if (!!hasColumn) return [3 /*break*/, 5];
                                    _c.label = 2;
                                case 2:
                                    _c.trys.push([2, 4, , 5]);
                                    return [4 /*yield*/, client_js_1.db.schema.alterTable(exports.BOARD_POST_REQUESTS_TABLE, function (table) {
                                            createColumn(table);
                                        })];
                                case 3:
                                    _c.sent();
                                    return [3 /*break*/, 5];
                                case 4:
                                    error_2 = _c.sent();
                                    if (!isDuplicateColumnError(error_2)) {
                                        throw error_2;
                                    }
                                    return [3 /*break*/, 5];
                                case 5: return [2 /*return*/];
                            }
                        });
                    };
                    _i = 0, requiredColumns_1 = requiredColumns;
                    _b.label = 6;
                case 6:
                    if (!(_i < requiredColumns_1.length)) return [3 /*break*/, 9];
                    _a = requiredColumns_1[_i], columnName = _a[0], createColumn = _a[1];
                    return [5 /*yield**/, _loop_1(columnName, createColumn)];
                case 7:
                    _b.sent();
                    _b.label = 8;
                case 8:
                    _i++;
                    return [3 /*break*/, 6];
                case 9: return [2 /*return*/];
            }
        });
    });
}
function syncLegacyBoardPostRequests() {
    return __awaiter(this, void 0, void 0, function () {
        var rows;
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0: return [4 /*yield*/, (0, client_js_1.db)(exports.BOARD_POSTS_TABLE)
                        .leftJoin(exports.BOARD_POST_REQUESTS_TABLE, "".concat(exports.BOARD_POSTS_TABLE, ".id"), "".concat(exports.BOARD_POST_REQUESTS_TABLE, ".board_post_id"))
                        .whereNull("".concat(exports.BOARD_POST_REQUESTS_TABLE, ".id"))
                        .select("".concat(exports.BOARD_POSTS_TABLE, ".id"), "".concat(exports.BOARD_POSTS_TABLE, ".title"), "".concat(exports.BOARD_POSTS_TABLE, ".content"), "".concat(exports.BOARD_POSTS_TABLE, ".automation_plan_item_id"), "".concat(exports.BOARD_POSTS_TABLE, ".automation_received_at"))];
                case 1:
                    rows = _a.sent();
                    if (!rows.length) {
                        return [2 /*return*/];
                    }
                    return [4 /*yield*/, (0, client_js_1.db)(exports.BOARD_POST_REQUESTS_TABLE).insert(rows.map(function (row) {
                            var _a, _b, _c;
                            return ({
                                board_post_id: Number(row.id),
                                sequence_no: 1,
                                title: String((_a = row.title) !== null && _a !== void 0 ? _a : '').trim() || '요청 1',
                                content: String((_b = row.content) !== null && _b !== void 0 ? _b : ''),
                                plan_item_id: row.automation_plan_item_id === null || row.automation_plan_item_id === undefined
                                    ? null
                                    : Number(row.automation_plan_item_id),
                                automation_received_at: (_c = row.automation_received_at) !== null && _c !== void 0 ? _c : null,
                                workflow_state: row.automation_plan_item_id || row.automation_received_at ? 'registered' : 'pending',
                                created_at: client_js_1.db.fn.now(),
                                updated_at: client_js_1.db.fn.now(),
                            });
                        }))];
                case 2:
                    _a.sent();
                    return [2 /*return*/];
            }
        });
    });
}
function ensureBoardPostsTable() {
    return __awaiter(this, void 0, void 0, function () {
        var hasTable, error_3, requiredColumns, _loop_2, _i, requiredColumns_2, _a, columnName, createColumn;
        return __generator(this, function (_b) {
            switch (_b.label) {
                case 0: return [4 /*yield*/, client_js_1.db.schema.hasTable(exports.BOARD_POSTS_TABLE)];
                case 1:
                    hasTable = _b.sent();
                    if (!!hasTable) return [3 /*break*/, 5];
                    _b.label = 2;
                case 2:
                    _b.trys.push([2, 4, , 5]);
                    return [4 /*yield*/, client_js_1.db.schema.createTable(exports.BOARD_POSTS_TABLE, function (table) {
                            table.increments('id').primary();
                            table.string('title', 200).notNullable();
                            table.text('content').notNullable();
                            table.timestamp('created_at', { useTz: true }).notNullable().defaultTo(client_js_1.db.fn.now());
                            table.timestamp('updated_at', { useTz: true }).notNullable().defaultTo(client_js_1.db.fn.now());
                        })];
                case 3:
                    _b.sent();
                    return [3 /*break*/, 5];
                case 4:
                    error_3 = _b.sent();
                    if (!isDuplicateTableError(error_3)) {
                        throw error_3;
                    }
                    return [3 /*break*/, 5];
                case 5:
                    requiredColumns = [
                        ['title', function (table) { return table.string('title', 200).notNullable().defaultTo('제목 없음'); }],
                        ['content', function (table) { return table.text('content').notNullable().defaultTo(''); }],
                        ['automation_type', function (table) { return table.string('automation_type', 40).notNullable().defaultTo('none'); }],
                        ['automation_type_id', function (table) { return table.string('automation_type_id', 120).nullable(); }],
                        ['attachments_json', function (table) { return table.text('attachments_json').notNullable().defaultTo('[]'); }],
                        ['automation_context_ids_json', function (table) { return table.text('automation_context_ids_json').notNullable().defaultTo('[]'); }],
                        ['request_execution_mode', function (table) { return table.string('request_execution_mode', 40).notNullable().defaultTo('all_at_once'); }],
                        ['automation_plan_item_id', function (table) { return table.integer('automation_plan_item_id').nullable(); }],
                        ['automation_received_at', function (table) { return table.timestamp('automation_received_at', { useTz: true }).nullable(); }],
                        ['created_at', function (table) { return table.timestamp('created_at', { useTz: true }).notNullable().defaultTo(client_js_1.db.fn.now()); }],
                        ['updated_at', function (table) { return table.timestamp('updated_at', { useTz: true }).notNullable().defaultTo(client_js_1.db.fn.now()); }],
                    ];
                    _loop_2 = function (columnName, createColumn) {
                        var hasColumn, error_4;
                        return __generator(this, function (_c) {
                            switch (_c.label) {
                                case 0: return [4 /*yield*/, client_js_1.db.schema.hasColumn(exports.BOARD_POSTS_TABLE, columnName)];
                                case 1:
                                    hasColumn = _c.sent();
                                    if (!!hasColumn) return [3 /*break*/, 5];
                                    _c.label = 2;
                                case 2:
                                    _c.trys.push([2, 4, , 5]);
                                    return [4 /*yield*/, client_js_1.db.schema.alterTable(exports.BOARD_POSTS_TABLE, function (table) {
                                            createColumn(table);
                                        })];
                                case 3:
                                    _c.sent();
                                    return [3 /*break*/, 5];
                                case 4:
                                    error_4 = _c.sent();
                                    if (!isDuplicateColumnError(error_4)) {
                                        throw error_4;
                                    }
                                    return [3 /*break*/, 5];
                                case 5: return [2 /*return*/];
                            }
                        });
                    };
                    _i = 0, requiredColumns_2 = requiredColumns;
                    _b.label = 6;
                case 6:
                    if (!(_i < requiredColumns_2.length)) return [3 /*break*/, 9];
                    _a = requiredColumns_2[_i], columnName = _a[0], createColumn = _a[1];
                    return [5 /*yield**/, _loop_2(columnName, createColumn)];
                case 7:
                    _b.sent();
                    _b.label = 8;
                case 8:
                    _i++;
                    return [3 /*break*/, 6];
                case 9: return [4 /*yield*/, (0, client_js_1.db)(exports.BOARD_POSTS_TABLE).where({ automation_type: 'plan_registration' }).update({ automation_type: 'plan' })];
                case 10:
                    _b.sent();
                    return [4 /*yield*/, (0, client_js_1.db)(exports.BOARD_POSTS_TABLE).where({ automation_type: 'general_development' }).update({ automation_type: 'auto_worker' })];
                case 11:
                    _b.sent();
                    return [4 /*yield*/, (0, client_js_1.db)(exports.BOARD_POSTS_TABLE).whereNull('automation_type_id').update({ automation_type_id: client_js_1.db.raw('automation_type') })];
                case 12:
                    _b.sent();
                    return [4 /*yield*/, ensureBoardPostRequestsTable()];
                case 13:
                    _b.sent();
                    return [4 /*yield*/, syncLegacyBoardPostRequests()];
                case 14:
                    _b.sent();
                    return [2 /*return*/];
            }
        });
    });
}
function mapBoardPostRequestRow(row, planRow) {
    var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
    var workflowState = resolveBoardRequestWorkflowState(row.workflow_state);
    var planStatus = (_a = planRow === null || planRow === void 0 ? void 0 : planRow.status) !== null && _a !== void 0 ? _a : null;
    var workerStatus = (_b = planRow === null || planRow === void 0 ? void 0 : planRow.worker_status) !== null && _b !== void 0 ? _b : null;
    var lastError = (_c = planRow === null || planRow === void 0 ? void 0 : planRow.last_error) !== null && _c !== void 0 ? _c : null;
    var resolvedStatus = resolveBoardRequestStatus({
        workflowState: workflowState,
        planStatus: planStatus,
        workerStatus: workerStatus,
        lastError: lastError,
    });
    return {
        id: Number((_d = row.id) !== null && _d !== void 0 ? _d : 0),
        boardPostId: Number((_e = row.board_post_id) !== null && _e !== void 0 ? _e : 0),
        sequence: Number((_f = row.sequence_no) !== null && _f !== void 0 ? _f : 0),
        title: String((_g = row.title) !== null && _g !== void 0 ? _g : ''),
        content: String((_h = row.content) !== null && _h !== void 0 ? _h : ''),
        planItemId: row.plan_item_id === null || row.plan_item_id === undefined ? null : Number(row.plan_item_id),
        automationReceivedAt: row.automation_received_at === null || row.automation_received_at === undefined
            ? null
            : String(row.automation_received_at),
        workflowState: workflowState,
        status: resolvedStatus.status,
        statusLabel: resolvedStatus.statusLabel,
        planStatus: planStatus,
        workerStatus: workerStatus,
        lastError: lastError,
        createdAt: String((_j = row.created_at) !== null && _j !== void 0 ? _j : ''),
        updatedAt: String((_k = row.updated_at) !== null && _k !== void 0 ? _k : ''),
    };
}
function buildBoardPostSummary(requestItems) {
    return requestItems.reduce(function (summary, requestItem) {
        summary.total += 1;
        if (requestItem.status === 'completed') {
            summary.completed += 1;
        }
        else if (requestItem.status === 'failed') {
            summary.failed += 1;
        }
        else if (requestItem.status === 'in_progress') {
            summary.running += 1;
        }
        else if (requestItem.status === 'queued') {
            summary.queued += 1;
        }
        else if (requestItem.status === 'waiting' || requestItem.status === 'pending') {
            summary.waiting += 1;
        }
        else if (requestItem.status === 'blocked') {
            summary.blocked += 1;
        }
        return summary;
    }, {
        total: 0,
        completed: 0,
        failed: 0,
        running: 0,
        queued: 0,
        waiting: 0,
        blocked: 0,
    });
}
function mapBoardPostRow(row, requestRows, planRowMap) {
    var _a, _b, _c, _d, _e, _f, _g, _h, _j;
    var content = String((_a = row.content) !== null && _a !== void 0 ? _a : '');
    var rawAttachments = (_c = (_b = row.attachments_json) !== null && _b !== void 0 ? _b : row.attachments) !== null && _c !== void 0 ? _c : '[]';
    var attachments = [];
    try {
        var parsed = typeof rawAttachments === 'string' ? JSON.parse(rawAttachments) : rawAttachments;
        attachments = exports.boardPostPayloadSchema.shape.attachments.parse(parsed);
    }
    catch (_k) {
        attachments = [];
    }
    var requestItems = requestRows
        .sort(function (left, right) { var _a, _b; return Number((_a = left.sequence_no) !== null && _a !== void 0 ? _a : 0) - Number((_b = right.sequence_no) !== null && _b !== void 0 ? _b : 0); })
        .map(function (requestRow) {
        var planItemId = requestRow.plan_item_id === null || requestRow.plan_item_id === undefined
            ? null
            : Number(requestRow.plan_item_id);
        return mapBoardPostRequestRow(requestRow, planItemId ? planRowMap.get(planItemId) : null);
    });
    var firstRegisteredRequest = requestItems.find(function (item) { return item.planItemId || item.automationReceivedAt; });
    var firstReceivedAt = (_d = requestItems
        .map(function (item) { return item.automationReceivedAt; })
        .filter(function (value) { return Boolean(value); })
        .sort()[0]) !== null && _d !== void 0 ? _d : null;
    return {
        id: Number((_e = row.id) !== null && _e !== void 0 ? _e : 0),
        title: String((_f = row.title) !== null && _f !== void 0 ? _f : ''),
        content: content,
        preview: createPreview(content || requestItems.map(function (item) { return item.content; }).join('\n\n')),
        attachments: attachments,
        automationType: (0, automation_type_config_service_js_1.resolveStoredAutomationTypeId)(row),
        automationPlanItemId: (_g = firstRegisteredRequest === null || firstRegisteredRequest === void 0 ? void 0 : firstRegisteredRequest.planItemId) !== null && _g !== void 0 ? _g : null,
        automationReceivedAt: firstReceivedAt,
        automationContextIds: (0, automation_context_service_js_1.parseAutomationContextIds)(row.automation_context_ids_json),
        requestExecutionMode: resolveBoardRequestExecutionMode(row.request_execution_mode),
        requestItems: requestItems,
        requestSummary: buildBoardPostSummary(requestItems),
        createdAt: String((_h = row.created_at) !== null && _h !== void 0 ? _h : ''),
        updatedAt: String((_j = row.updated_at) !== null && _j !== void 0 ? _j : ''),
    };
}
function loadBoardPostsWithRequests(postIds) {
    return __awaiter(this, void 0, void 0, function () {
        var postQuery, rows, boardPostIds, requestRows, planItemIds, planRows, _a, requestRowsByPostId, planRowMap, _i, requestRows_1, requestRow, boardPostId, currentRows, _b, planRows_1, planRow;
        var _c, _d;
        return __generator(this, function (_e) {
            switch (_e.label) {
                case 0: return [4 /*yield*/, ensureBoardPostsTable()];
                case 1:
                    _e.sent();
                    postQuery = (0, client_js_1.db)(exports.BOARD_POSTS_TABLE).select('*').orderBy('updated_at', 'desc').orderBy('id', 'desc');
                    if (postIds === null || postIds === void 0 ? void 0 : postIds.length) {
                        postQuery.whereIn('id', postIds);
                    }
                    return [4 /*yield*/, postQuery];
                case 2:
                    rows = _e.sent();
                    if (!rows.length) {
                        return [2 /*return*/, []];
                    }
                    boardPostIds = rows.map(function (row) { return Number(row.id); });
                    return [4 /*yield*/, (0, client_js_1.db)(exports.BOARD_POST_REQUESTS_TABLE)
                            .select('*')
                            .whereIn('board_post_id', boardPostIds)
                            .orderBy('sequence_no', 'asc')
                            .orderBy('id', 'asc')];
                case 3:
                    requestRows = _e.sent();
                    planItemIds = requestRows
                        .map(function (row) { return Number(row.plan_item_id); })
                        .filter(function (value) { return Number.isFinite(value) && value > 0; });
                    if (!(planItemIds.length > 0)) return [3 /*break*/, 5];
                    return [4 /*yield*/, (0, client_js_1.db)(plan_service_js_1.PLAN_TABLE).select('id', 'status', 'worker_status', 'last_error').whereIn('id', planItemIds)];
                case 4:
                    _a = _e.sent();
                    return [3 /*break*/, 6];
                case 5:
                    _a = [];
                    _e.label = 6;
                case 6:
                    planRows = _a;
                    requestRowsByPostId = new Map();
                    planRowMap = new Map();
                    for (_i = 0, requestRows_1 = requestRows; _i < requestRows_1.length; _i++) {
                        requestRow = requestRows_1[_i];
                        boardPostId = Number((_c = requestRow.board_post_id) !== null && _c !== void 0 ? _c : 0);
                        currentRows = (_d = requestRowsByPostId.get(boardPostId)) !== null && _d !== void 0 ? _d : [];
                        currentRows.push(requestRow);
                        requestRowsByPostId.set(boardPostId, currentRows);
                    }
                    for (_b = 0, planRows_1 = planRows; _b < planRows_1.length; _b++) {
                        planRow = planRows_1[_b];
                        planRowMap.set(Number(planRow.id), {
                            id: Number(planRow.id),
                            status: planRow.status === null || planRow.status === undefined ? null : String(planRow.status),
                            worker_status: planRow.worker_status === null || planRow.worker_status === undefined ? null : String(planRow.worker_status),
                            last_error: planRow.last_error === null || planRow.last_error === undefined ? null : String(planRow.last_error),
                        });
                    }
                    return [2 /*return*/, rows.map(function (row) { var _a; return mapBoardPostRow(row, (_a = requestRowsByPostId.get(Number(row.id))) !== null && _a !== void 0 ? _a : [], planRowMap); })];
            }
        });
    });
}
function getExistingPlanWorkIds(trx) {
    return __awaiter(this, void 0, void 0, function () {
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0: return [4 /*yield*/, trx(plan_service_js_1.PLAN_TABLE).select('work_id')];
                case 1: return [2 /*return*/, (_a.sent()).map(function (row) { var _a; return String((_a = row.work_id) !== null && _a !== void 0 ? _a : ''); })];
            }
        });
    });
}
function createPlanFromBoardRequest(trx, args) {
    return __awaiter(this, void 0, void 0, function () {
        var boardPost, automationType, existingWorkIds, suffixLabel, workId, insertQuery, _a, _b, insertResult, _c, planItemId;
        var _d;
        var _e, _f, _g, _h, _j, _k, _l, _m, _o;
        return __generator(this, function (_p) {
            switch (_p.label) {
                case 0:
                    boardPost = mapBoardPostRow(args.boardPostRow, [args.requestRow], new Map());
                    return [4 /*yield*/, (0, automation_type_config_service_js_1.resolveAutomationType)((_e = args.boardPostRow.automation_type_id) !== null && _e !== void 0 ? _e : args.boardPostRow.automation_type)];
                case 1:
                    automationType = _p.sent();
                    return [4 /*yield*/, getExistingPlanWorkIds(trx)];
                case 2:
                    existingWorkIds = _p.sent();
                    suffixLabel = ((_f = args.planWorkIdSuffixLabel) === null || _f === void 0 ? void 0 : _f.trim()) || "req-".concat(Number((_g = args.requestRow.sequence_no) !== null && _g !== void 0 ? _g : 1));
                    workId = ((_h = args.planWorkIdBase) === null || _h === void 0 ? void 0 : _h.trim())
                        ? resolveSequencedPlanWorkId(args.planWorkIdBase, existingWorkIds, suffixLabel)
                        : "board-post-".concat(Number(args.boardPostRow.id), "-req-").concat(Number((_j = args.requestRow.sequence_no) !== null && _j !== void 0 ? _j : 1));
                    _b = (_a = trx(plan_service_js_1.PLAN_TABLE)).insert;
                    _d = {
                        work_id: workId
                    };
                    return [4 /*yield*/, buildBoardPostPlanNote(boardPost.title, boardPost.content, boardPost.attachments, automationType, boardPost.automationContextIds, undefined, {
                            title: String((_k = args.requestRow.title) !== null && _k !== void 0 ? _k : ''),
                            content: String((_l = args.requestRow.content) !== null && _l !== void 0 ? _l : ''),
                        }, args.sequenceInfo)];
                case 3:
                    insertQuery = _b.apply(_a, [(_d.note = _p.sent(),
                            _d.automation_type = (0, plan_service_js_1.normalizePlanAutomationType)(args.boardPostRow.automation_type),
                            _d.automation_type_id = (_m = args.boardPostRow.automation_type_id) !== null && _m !== void 0 ? _m : args.boardPostRow.automation_type,
                            _d.automation_context_ids_json = (0, automation_context_service_js_1.stringifyAutomationContextIds)(boardPost.automationContextIds),
                            _d.status = '등록',
                            _d.release_target = 'release',
                            _d.jangsing_processing_required = true,
                            _d.auto_deploy_to_main = false,
                            _d.suppress_web_push = (_o = args.suppressWebPush) !== null && _o !== void 0 ? _o : false,
                            _d.worker_status = '대기',
                            _d.last_error = null,
                            _d.updated_at = trx.fn.now(),
                            _d)]);
                    if (!supportsReturning()) return [3 /*break*/, 5];
                    return [4 /*yield*/, insertQuery.returning('id')];
                case 4:
                    _c = _p.sent();
                    return [3 /*break*/, 7];
                case 5: return [4 /*yield*/, insertQuery];
                case 6:
                    _c = _p.sent();
                    _p.label = 7;
                case 7:
                    insertResult = _c;
                    planItemId = resolveInsertedId(insertResult);
                    if (!planItemId) {
                        throw new Error('자동화 접수 후 Plan ID를 확인하지 못했습니다.');
                    }
                    return [4 /*yield*/, trx(exports.BOARD_POST_REQUESTS_TABLE)
                            .where({ id: Number(args.requestRow.id) })
                            .update({
                            plan_item_id: planItemId,
                            automation_received_at: trx.fn.now(),
                            workflow_state: 'registered',
                            updated_at: trx.fn.now(),
                        })];
                case 8:
                    _p.sent();
                    return [2 /*return*/, planItemId];
            }
        });
    });
}
function syncBoardPostLegacyLinkColumns(trx, boardPostId) {
    return __awaiter(this, void 0, void 0, function () {
        var requestRows, firstRegisteredRequest, firstReceivedAt;
        var _a;
        return __generator(this, function (_b) {
            switch (_b.label) {
                case 0: return [4 /*yield*/, trx(exports.BOARD_POST_REQUESTS_TABLE)
                        .select('plan_item_id', 'automation_received_at')
                        .where({ board_post_id: boardPostId })
                        .orderBy('sequence_no', 'asc')
                        .orderBy('id', 'asc')];
                case 1:
                    requestRows = _b.sent();
                    firstRegisteredRequest = requestRows.find(function (row) { return row.plan_item_id || row.automation_received_at; });
                    firstReceivedAt = (_a = requestRows
                        .map(function (row) { return row.automation_received_at; })
                        .filter(function (value) { return Boolean(value); })
                        .sort()[0]) !== null && _a !== void 0 ? _a : null;
                    return [4 /*yield*/, trx(exports.BOARD_POSTS_TABLE)
                            .where({ id: boardPostId })
                            .update({
                            automation_plan_item_id: (firstRegisteredRequest === null || firstRegisteredRequest === void 0 ? void 0 : firstRegisteredRequest.plan_item_id) === null || (firstRegisteredRequest === null || firstRegisteredRequest === void 0 ? void 0 : firstRegisteredRequest.plan_item_id) === undefined
                                ? null
                                : Number(firstRegisteredRequest.plan_item_id),
                            automation_received_at: firstReceivedAt,
                            updated_at: trx.fn.now(),
                        })];
                case 2:
                    _b.sent();
                    return [2 /*return*/];
            }
        });
    });
}
function isBoardPostAutomationLocked(requestRows, row) {
    if (row.automation_received_at || row.automation_plan_item_id) {
        return true;
    }
    return requestRows.some(function (requestRow) { return requestRow.automation_received_at || requestRow.plan_item_id; });
}
function listBoardPosts() {
    return __awaiter(this, void 0, void 0, function () {
        return __generator(this, function (_a) {
            return [2 /*return*/, loadBoardPostsWithRequests()];
        });
    });
}
function getBoardPost(id) {
    return __awaiter(this, void 0, void 0, function () {
        var items;
        var _a;
        return __generator(this, function (_b) {
            switch (_b.label) {
                case 0: return [4 /*yield*/, loadBoardPostsWithRequests([id])];
                case 1:
                    items = _b.sent();
                    return [2 /*return*/, (_a = items[0]) !== null && _a !== void 0 ? _a : null];
            }
        });
    });
}
function createBoardPost(payload) {
    return __awaiter(this, void 0, void 0, function () {
        var parsedPayload, normalizedRequestItems, automationType, insertQuery, insertResult, _a, insertedId, item;
        return __generator(this, function (_b) {
            switch (_b.label) {
                case 0: return [4 /*yield*/, ensureBoardPostsTable()];
                case 1:
                    _b.sent();
                    parsedPayload = exports.boardPostPayloadSchema.parse(payload);
                    normalizedRequestItems = normalizeBoardPostRequestItems(parsedPayload.requestItems, parsedPayload.title, parsedPayload.content);
                    return [4 /*yield*/, (0, automation_type_config_service_js_1.resolveAutomationType)(parsedPayload.automationType)];
                case 2:
                    automationType = _b.sent();
                    insertQuery = (0, client_js_1.db)(exports.BOARD_POSTS_TABLE).insert({
                        title: parsedPayload.title,
                        content: parsedPayload.content,
                        attachments_json: JSON.stringify(parsedPayload.attachments),
                        automation_type: automationType.behaviorType,
                        automation_type_id: automationType.id,
                        automation_context_ids_json: (0, automation_context_service_js_1.stringifyAutomationContextIds)(parsedPayload.automationContextIds),
                        request_execution_mode: parsedPayload.requestExecutionMode,
                        created_at: client_js_1.db.fn.now(),
                        updated_at: client_js_1.db.fn.now(),
                    });
                    if (!supportsReturning()) return [3 /*break*/, 4];
                    return [4 /*yield*/, insertQuery.returning('id')];
                case 3:
                    _a = _b.sent();
                    return [3 /*break*/, 6];
                case 4: return [4 /*yield*/, insertQuery];
                case 5:
                    _a = _b.sent();
                    _b.label = 6;
                case 6:
                    insertResult = _a;
                    insertedId = resolveInsertedId(insertResult);
                    if (!insertedId) {
                        throw new Error('게시글 저장 후 ID를 확인하지 못했습니다.');
                    }
                    return [4 /*yield*/, (0, client_js_1.db)(exports.BOARD_POST_REQUESTS_TABLE).insert(normalizedRequestItems.map(function (requestItem, index) { return ({
                            board_post_id: insertedId,
                            sequence_no: index + 1,
                            title: requestItem.title,
                            content: requestItem.content,
                            workflow_state: 'pending',
                            created_at: client_js_1.db.fn.now(),
                            updated_at: client_js_1.db.fn.now(),
                        }); }))];
                case 7:
                    _b.sent();
                    return [4 /*yield*/, getBoardPost(insertedId)];
                case 8:
                    item = _b.sent();
                    if (!item) {
                        throw new Error('저장된 게시글을 다시 불러오지 못했습니다.');
                    }
                    return [2 /*return*/, item];
            }
        });
    });
}
function receiveBoardPostAutomation(id, options) {
    return __awaiter(this, void 0, void 0, function () {
        var transactionResult;
        var _a;
        var _this = this;
        return __generator(this, function (_b) {
            switch (_b.label) {
                case 0: return [4 /*yield*/, ensureBoardPostsTable()];
                case 1:
                    _b.sent();
                    return [4 /*yield*/, (0, plan_service_js_1.ensurePlanTable)()];
                case 2:
                    _b.sent();
                    return [4 /*yield*/, client_js_1.db.transaction(function (trx) { return __awaiter(_this, void 0, void 0, function () {
                            var currentRow, requestRows, requestExecutionMode, registeredPlanItemIds, pendingRequestRows, targetRequestRows, firstPendingRequest, waitingIds, createdPlanItemIds, _i, targetRequestRows_1, requestRow, _a, _b;
                            var _c;
                            return __generator(this, function (_d) {
                                switch (_d.label) {
                                    case 0: return [4 /*yield*/, trx(exports.BOARD_POSTS_TABLE).where({ id: id }).forUpdate().first()];
                                    case 1:
                                        currentRow = _d.sent();
                                        if (!currentRow) {
                                            return [2 /*return*/, null];
                                        }
                                        return [4 /*yield*/, trx(exports.BOARD_POST_REQUESTS_TABLE)
                                                .where({ board_post_id: id })
                                                .orderBy('sequence_no', 'asc')
                                                .orderBy('id', 'asc')
                                                .forUpdate()];
                                    case 2:
                                        requestRows = _d.sent();
                                        requestExecutionMode = resolveBoardRequestExecutionMode(currentRow.request_execution_mode);
                                        registeredPlanItemIds = requestRows
                                            .map(function (requestRow) { return Number(requestRow.plan_item_id); })
                                            .filter(function (value) { return Number.isFinite(value) && value > 0; });
                                        pendingRequestRows = requestRows.filter(function (requestRow) { return !requestRow.plan_item_id && !requestRow.automation_received_at; });
                                        targetRequestRows = [];
                                        if (!(requestExecutionMode === 'all_at_once')) return [3 /*break*/, 3];
                                        targetRequestRows = pendingRequestRows.filter(function (requestRow) { return resolveBoardRequestWorkflowState(requestRow.workflow_state) !== 'blocked'; });
                                        return [3 /*break*/, 5];
                                    case 3:
                                        if (!(registeredPlanItemIds.length === 0)) return [3 /*break*/, 5];
                                        firstPendingRequest = pendingRequestRows[0];
                                        if (firstPendingRequest) {
                                            targetRequestRows = [firstPendingRequest];
                                        }
                                        waitingIds = pendingRequestRows.slice(1).map(function (requestRow) { return Number(requestRow.id); }).filter(Number.isFinite);
                                        if (!(waitingIds.length > 0)) return [3 /*break*/, 5];
                                        return [4 /*yield*/, trx(exports.BOARD_POST_REQUESTS_TABLE)
                                                .whereIn('id', waitingIds)
                                                .update({
                                                workflow_state: 'waiting',
                                                updated_at: trx.fn.now(),
                                            })];
                                    case 4:
                                        _d.sent();
                                        _d.label = 5;
                                    case 5:
                                        if (targetRequestRows.length === 0) {
                                            return [2 /*return*/, {
                                                    planItemIds: registeredPlanItemIds,
                                                    alreadyReceived: true,
                                                }];
                                        }
                                        createdPlanItemIds = [];
                                        _i = 0, targetRequestRows_1 = targetRequestRows;
                                        _d.label = 6;
                                    case 6:
                                        if (!(_i < targetRequestRows_1.length)) return [3 /*break*/, 9];
                                        requestRow = targetRequestRows_1[_i];
                                        _b = (_a = createdPlanItemIds).push;
                                        return [4 /*yield*/, createPlanFromBoardRequest(trx, {
                                                boardPostRow: currentRow,
                                                requestRow: requestRow,
                                                sequenceInfo: {
                                                    index: Number((_c = requestRow.sequence_no) !== null && _c !== void 0 ? _c : 1),
                                                    total: requestRows.length,
                                                },
                                                planWorkIdBase: options === null || options === void 0 ? void 0 : options.planWorkIdBase,
                                                planWorkIdSuffixLabel: options === null || options === void 0 ? void 0 : options.planWorkIdSuffixLabel,
                                                suppressWebPush: options === null || options === void 0 ? void 0 : options.suppressWebPush,
                                            })];
                                    case 7:
                                        _b.apply(_a, [_d.sent()]);
                                        _d.label = 8;
                                    case 8:
                                        _i++;
                                        return [3 /*break*/, 6];
                                    case 9: return [4 /*yield*/, syncBoardPostLegacyLinkColumns(trx, id)];
                                    case 10:
                                        _d.sent();
                                        return [2 /*return*/, {
                                                planItemIds: createdPlanItemIds,
                                                alreadyReceived: false,
                                            }];
                                }
                            });
                        }); })];
                case 3:
                    transactionResult = _b.sent();
                    if (!transactionResult) {
                        return [2 /*return*/, null];
                    }
                    _a = {};
                    return [4 /*yield*/, getBoardPost(id)];
                case 4: return [2 /*return*/, __assign.apply(void 0, [(_a.item = _b.sent(), _a), transactionResult])];
            }
        });
    });
}
function progressBoardPostAutomationByPlanResult(planItemId, outcome) {
    return __awaiter(this, void 0, void 0, function () {
        var updatedBoardPostId;
        var _this = this;
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0: return [4 /*yield*/, ensureBoardPostsTable()];
                case 1:
                    _a.sent();
                    return [4 /*yield*/, (0, plan_service_js_1.ensurePlanTable)()];
                case 2:
                    _a.sent();
                    return [4 /*yield*/, client_js_1.db.transaction(function (trx) { return __awaiter(_this, void 0, void 0, function () {
                            var currentRequestRow, boardPostId, boardPostRow, requestExecutionMode, requestRows, nextWaitingRequest, blockedRequestIds;
                            var _a;
                            return __generator(this, function (_b) {
                                switch (_b.label) {
                                    case 0: return [4 /*yield*/, trx(exports.BOARD_POST_REQUESTS_TABLE).where({ plan_item_id: planItemId }).forUpdate().first()];
                                    case 1:
                                        currentRequestRow = _b.sent();
                                        if (!currentRequestRow) {
                                            return [2 /*return*/, null];
                                        }
                                        boardPostId = Number(currentRequestRow.board_post_id);
                                        return [4 /*yield*/, trx(exports.BOARD_POSTS_TABLE).where({ id: boardPostId }).forUpdate().first()];
                                    case 2:
                                        boardPostRow = _b.sent();
                                        if (!boardPostRow) {
                                            return [2 /*return*/, null];
                                        }
                                        requestExecutionMode = resolveBoardRequestExecutionMode(boardPostRow.request_execution_mode);
                                        return [4 /*yield*/, trx(exports.BOARD_POST_REQUESTS_TABLE)
                                                .where({ board_post_id: boardPostId })
                                                .orderBy('sequence_no', 'asc')
                                                .orderBy('id', 'asc')
                                                .forUpdate()];
                                    case 3:
                                        requestRows = _b.sent();
                                        return [4 /*yield*/, trx(exports.BOARD_POST_REQUESTS_TABLE)
                                                .where({ id: Number(currentRequestRow.id) })
                                                .update({
                                                workflow_state: outcome === 'completed' ? 'completed' : 'failed',
                                                updated_at: trx.fn.now(),
                                            })];
                                    case 4:
                                        _b.sent();
                                        if (!(requestExecutionMode === 'all_at_once')) return [3 /*break*/, 6];
                                        return [4 /*yield*/, syncBoardPostLegacyLinkColumns(trx, boardPostId)];
                                    case 5:
                                        _b.sent();
                                        return [2 /*return*/, boardPostId];
                                    case 6:
                                        nextWaitingRequest = requestRows.find(function (requestRow) {
                                            if (Number(requestRow.id) === Number(currentRequestRow.id)) {
                                                return false;
                                            }
                                            var state = resolveBoardRequestWorkflowState(requestRow.workflow_state);
                                            return !requestRow.plan_item_id && !requestRow.automation_received_at && (state === 'waiting' || state === 'pending');
                                        });
                                        if (!!nextWaitingRequest) return [3 /*break*/, 8];
                                        return [4 /*yield*/, syncBoardPostLegacyLinkColumns(trx, boardPostId)];
                                    case 7:
                                        _b.sent();
                                        return [2 /*return*/, boardPostId];
                                    case 8:
                                        if (!(requestExecutionMode === 'after_previous_success' && outcome === 'failed')) return [3 /*break*/, 11];
                                        blockedRequestIds = requestRows
                                            .filter(function (requestRow) { var _a, _b; return Number((_a = requestRow.sequence_no) !== null && _a !== void 0 ? _a : 0) > Number((_b = currentRequestRow.sequence_no) !== null && _b !== void 0 ? _b : 0); })
                                            .map(function (requestRow) { return Number(requestRow.id); })
                                            .filter(Number.isFinite);
                                        if (!(blockedRequestIds.length > 0)) return [3 /*break*/, 10];
                                        return [4 /*yield*/, trx(exports.BOARD_POST_REQUESTS_TABLE)
                                                .whereIn('id', blockedRequestIds)
                                                .update({
                                                workflow_state: 'blocked',
                                                updated_at: trx.fn.now(),
                                            })];
                                    case 9:
                                        _b.sent();
                                        _b.label = 10;
                                    case 10: return [3 /*break*/, 13];
                                    case 11: return [4 /*yield*/, createPlanFromBoardRequest(trx, {
                                            boardPostRow: boardPostRow,
                                            requestRow: nextWaitingRequest,
                                            sequenceInfo: {
                                                index: Number((_a = nextWaitingRequest.sequence_no) !== null && _a !== void 0 ? _a : 1),
                                                total: requestRows.length,
                                            },
                                        })];
                                    case 12:
                                        _b.sent();
                                        _b.label = 13;
                                    case 13: return [4 /*yield*/, syncBoardPostLegacyLinkColumns(trx, boardPostId)];
                                    case 14:
                                        _b.sent();
                                        return [2 /*return*/, boardPostId];
                                }
                            });
                        }); })];
                case 3:
                    updatedBoardPostId = _a.sent();
                    if (!updatedBoardPostId) {
                        return [2 /*return*/, null];
                    }
                    return [2 /*return*/, getBoardPost(updatedBoardPostId)];
            }
        });
    });
}
function updateBoardPost(id, payload) {
    return __awaiter(this, void 0, void 0, function () {
        var parsedPayload, normalizedRequestItems, automationType, updatedBoardPostId;
        var _this = this;
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0: return [4 /*yield*/, ensureBoardPostsTable()];
                case 1:
                    _a.sent();
                    parsedPayload = exports.boardPostPayloadSchema.parse(payload);
                    normalizedRequestItems = normalizeBoardPostRequestItems(parsedPayload.requestItems, parsedPayload.title, parsedPayload.content);
                    return [4 /*yield*/, (0, automation_type_config_service_js_1.resolveAutomationType)(parsedPayload.automationType)];
                case 2:
                    automationType = _a.sent();
                    return [4 /*yield*/, client_js_1.db.transaction(function (trx) { return __awaiter(_this, void 0, void 0, function () {
                            var currentRow, currentRequestRows;
                            return __generator(this, function (_a) {
                                switch (_a.label) {
                                    case 0: return [4 /*yield*/, trx(exports.BOARD_POSTS_TABLE).where({ id: id }).forUpdate().first()];
                                    case 1:
                                        currentRow = _a.sent();
                                        if (!currentRow) {
                                            return [2 /*return*/, null];
                                        }
                                        return [4 /*yield*/, trx(exports.BOARD_POST_REQUESTS_TABLE)
                                                .where({ board_post_id: id })
                                                .orderBy('sequence_no', 'asc')
                                                .orderBy('id', 'asc')
                                                .forUpdate()];
                                    case 2:
                                        currentRequestRows = _a.sent();
                                        if (isBoardPostAutomationLocked(currentRequestRows, currentRow)) {
                                            throw new BoardPostAutomationLockedError('update');
                                        }
                                        return [4 /*yield*/, trx(exports.BOARD_POSTS_TABLE)
                                                .where({ id: id })
                                                .update({
                                                title: parsedPayload.title,
                                                content: parsedPayload.content,
                                                attachments_json: JSON.stringify(parsedPayload.attachments),
                                                automation_type: automationType.behaviorType,
                                                automation_type_id: automationType.id,
                                                automation_context_ids_json: (0, automation_context_service_js_1.stringifyAutomationContextIds)(parsedPayload.automationContextIds),
                                                request_execution_mode: parsedPayload.requestExecutionMode,
                                                updated_at: trx.fn.now(),
                                            })];
                                    case 3:
                                        _a.sent();
                                        return [4 /*yield*/, trx(exports.BOARD_POST_REQUESTS_TABLE).where({ board_post_id: id }).delete()];
                                    case 4:
                                        _a.sent();
                                        return [4 /*yield*/, trx(exports.BOARD_POST_REQUESTS_TABLE).insert(normalizedRequestItems.map(function (requestItem, index) { return ({
                                                board_post_id: id,
                                                sequence_no: index + 1,
                                                title: requestItem.title,
                                                content: requestItem.content,
                                                workflow_state: 'pending',
                                                created_at: trx.fn.now(),
                                                updated_at: trx.fn.now(),
                                            }); }))];
                                    case 5:
                                        _a.sent();
                                        return [2 /*return*/, id];
                                }
                            });
                        }); })];
                case 3:
                    updatedBoardPostId = _a.sent();
                    if (!updatedBoardPostId) {
                        return [2 /*return*/, null];
                    }
                    return [2 /*return*/, getBoardPost(updatedBoardPostId)];
            }
        });
    });
}
function deleteBoardPost(id) {
    return __awaiter(this, void 0, void 0, function () {
        var _this = this;
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0: return [4 /*yield*/, ensureBoardPostsTable()];
                case 1:
                    _a.sent();
                    return [2 /*return*/, client_js_1.db.transaction(function (trx) { return __awaiter(_this, void 0, void 0, function () {
                            var currentRow, currentRequestRows, deletedCount;
                            return __generator(this, function (_a) {
                                switch (_a.label) {
                                    case 0: return [4 /*yield*/, trx(exports.BOARD_POSTS_TABLE).where({ id: id }).forUpdate().first()];
                                    case 1:
                                        currentRow = _a.sent();
                                        if (!currentRow) {
                                            return [2 /*return*/, false];
                                        }
                                        return [4 /*yield*/, trx(exports.BOARD_POST_REQUESTS_TABLE)
                                                .where({ board_post_id: id })
                                                .forUpdate()];
                                    case 2:
                                        currentRequestRows = _a.sent();
                                        if (isBoardPostAutomationLocked(currentRequestRows, currentRow)) {
                                            throw new BoardPostAutomationLockedError('delete');
                                        }
                                        return [4 /*yield*/, trx(exports.BOARD_POST_REQUESTS_TABLE).where({ board_post_id: id }).delete()];
                                    case 3:
                                        _a.sent();
                                        return [4 /*yield*/, trx(exports.BOARD_POSTS_TABLE).where({ id: id }).del()];
                                    case 4:
                                        deletedCount = _a.sent();
                                        return [2 /*return*/, deletedCount > 0];
                                }
                            });
                        }); })];
            }
        });
    });
}
