"use strict";
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 };
    }
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.updatePlanScheduledTaskSchema = exports.createPlanScheduledTaskSchema = exports.PLAN_SCHEDULED_TASK_TABLE = void 0;
exports.buildScheduledBoardPostTitle = buildScheduledBoardPostTitle;
exports.buildScheduledPlanWorkIdBase = buildScheduledPlanWorkIdBase;
exports.shouldCreatePlanForScheduleExecution = shouldCreatePlanForScheduleExecution;
exports.isPlanScheduledTaskDue = isPlanScheduledTaskDue;
exports.mapPlanScheduledTaskRow = mapPlanScheduledTaskRow;
exports.ensurePlanScheduledTaskTable = ensurePlanScheduledTaskTable;
exports.listPlanScheduledTasks = listPlanScheduledTasks;
exports.getPlanScheduledTaskById = getPlanScheduledTaskById;
exports.syncManagedServiceGenerationCompletion = syncManagedServiceGenerationCompletion;
exports.createPlanScheduledTask = createPlanScheduledTask;
exports.updatePlanScheduledTask = updatePlanScheduledTask;
exports.deletePlanScheduledTask = deletePlanScheduledTask;
exports.registerDuePlanScheduledTasks = registerDuePlanScheduledTasks;
exports.registerPlanScheduledTaskNow = registerPlanScheduledTaskNow;
var zod_1 = require("zod");
var client_js_1 = require("../db/client.js");
var automation_type_config_service_js_1 = require("./automation-type-config-service.js");
var board_service_js_1 = require("./board-service.js");
var managed_schedule_service_js_1 = require("./managed-schedule-service.js");
var automation_context_service_js_1 = require("./automation-context-service.js");
var plan_service_js_1 = require("./plan-service.js");
var worklog_automation_utils_js_1 = require("./worklog-automation-utils.js");
exports.PLAN_SCHEDULED_TASK_TABLE = 'plan_scheduled_tasks';
var scheduleModes = ['interval', 'daily'];
var repeatIntervalUnits = ['second', 'minute', 'hour', 'day', 'week', 'month'];
var scheduleExecutionModes = ['codex', 'managed-service'];
var DEFAULT_DAILY_RUN_TIME = '09:00';
var TIME_OF_DAY_PATTERN = /^([01]\d|2[0-3]):[0-5]\d$/;
var DATE_KEY_PATTERN = /^\d{4}-\d{2}-\d{2}$/;
var MAX_REPEAT_INTERVAL_SECONDS = 31536000;
var DEFAULT_REPEAT_INTERVAL_SECONDS = 60 * 60;
var scheduleDateRangeSchema = zod_1.z
    .object({
    startDate: zod_1.z.string().regex(DATE_KEY_PATTERN),
    endDate: zod_1.z.string().regex(DATE_KEY_PATTERN),
})
    .superRefine(function (value, context) {
    if (value.startDate > value.endDate) {
        context.addIssue({
            code: zod_1.z.ZodIssueCode.custom,
            message: '시작일은 종료일보다 늦을 수 없습니다.',
            path: ['endDate'],
        });
    }
});
var scheduleWeekdaySchema = zod_1.z.number().int().min(0).max(6);
var scheduleTimeWindowSchema = zod_1.z
    .object({
    startTime: zod_1.z.string().regex(TIME_OF_DAY_PATTERN).nullable().optional().default(null),
    endTime: zod_1.z.string().regex(TIME_OF_DAY_PATTERN).nullable().optional().default(null),
})
    .refine(function (value) { return Boolean(value.startTime || value.endTime); }, {
    message: '시작시간 또는 종료시간 중 하나는 입력해야 합니다.',
});
exports.createPlanScheduledTaskSchema = zod_1.z.object({
    workId: zod_1.z.string().trim().optional().default('반복작업'),
    note: zod_1.z.string().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([]),
    releaseTarget: zod_1.z.string().trim().min(1).default('release'),
    jangsingProcessingRequired: zod_1.z.boolean().default(true),
    autoDeployToMain: zod_1.z.boolean().default(true),
    suppressWebPush: zod_1.z.boolean().default(false),
    enabled: zod_1.z.boolean().default(true),
    immediateRunEnabled: zod_1.z.boolean().default(true),
    refreshContextSnapshotOnNextRun: zod_1.z.boolean().default(false),
    executionMode: zod_1.z.enum(scheduleExecutionModes).default('codex'),
    recreateManagedServiceOnNextSave: zod_1.z.boolean().default(false),
    scheduleMode: zod_1.z.enum(scheduleModes).default('interval'),
    repeatIntervalValue: zod_1.z.coerce.number().int().min(1).max(MAX_REPEAT_INTERVAL_SECONDS).default(60),
    repeatIntervalUnit: zod_1.z.enum(repeatIntervalUnits).default('minute'),
    repeatIntervalMinutes: zod_1.z.coerce.number().int().min(1).max(525600).optional(),
    repeatIntervalSeconds: zod_1.z.coerce.number().int().min(1).max(MAX_REPEAT_INTERVAL_SECONDS).optional(),
    dailyRunTime: zod_1.z.string().regex(/^([01]\d|2[0-3]):[0-5]\d$/).default(DEFAULT_DAILY_RUN_TIME),
    scheduleWeekdays: zod_1.z.array(scheduleWeekdaySchema).max(7).optional().default([]),
    scheduleDateRanges: zod_1.z.array(scheduleDateRangeSchema).max(40).optional().default([]),
    repeatWindows: zod_1.z.array(scheduleTimeWindowSchema).max(24).optional().default([]),
    repeatWindowStartTime: zod_1.z.string().regex(TIME_OF_DAY_PATTERN).nullable().optional().default(null),
    repeatWindowEndTime: zod_1.z.string().regex(TIME_OF_DAY_PATTERN).nullable().optional().default(null),
});
exports.updatePlanScheduledTaskSchema = zod_1.z.object({
    workId: zod_1.z.string().trim().optional(),
    note: zod_1.z.string().optional(),
    automationType: zod_1.z.preprocess(function (value) { return value; }, plan_service_js_1.planAutomationTypeSchema.optional()),
    automationContextIds: zod_1.z.array(zod_1.z.string().trim().min(1).max(160)).max(20).optional(),
    releaseTarget: zod_1.z.string().trim().min(1).optional(),
    jangsingProcessingRequired: zod_1.z.boolean().optional(),
    autoDeployToMain: zod_1.z.boolean().optional(),
    suppressWebPush: zod_1.z.boolean().optional(),
    enabled: zod_1.z.boolean().optional(),
    immediateRunEnabled: zod_1.z.boolean().optional(),
    refreshContextSnapshotOnNextRun: zod_1.z.boolean().optional(),
    executionMode: zod_1.z.enum(scheduleExecutionModes).optional(),
    recreateManagedServiceOnNextSave: zod_1.z.boolean().optional(),
    scheduleMode: zod_1.z.enum(scheduleModes).optional(),
    repeatIntervalValue: zod_1.z.coerce.number().int().min(1).max(MAX_REPEAT_INTERVAL_SECONDS).optional(),
    repeatIntervalUnit: zod_1.z.enum(repeatIntervalUnits).optional(),
    repeatIntervalMinutes: zod_1.z.coerce.number().int().min(1).max(525600).optional(),
    repeatIntervalSeconds: zod_1.z.coerce.number().int().min(1).max(MAX_REPEAT_INTERVAL_SECONDS).optional(),
    dailyRunTime: zod_1.z.string().regex(TIME_OF_DAY_PATTERN).optional(),
    scheduleWeekdays: zod_1.z.array(scheduleWeekdaySchema).max(7).optional(),
    scheduleDateRanges: zod_1.z.array(scheduleDateRangeSchema).max(40).optional(),
    repeatWindows: zod_1.z.array(scheduleTimeWindowSchema).max(24).optional(),
    repeatWindowStartTime: zod_1.z.string().regex(TIME_OF_DAY_PATTERN).nullable().optional(),
    repeatWindowEndTime: zod_1.z.string().regex(TIME_OF_DAY_PATTERN).nullable().optional(),
});
function normalizeScheduledWorkId(value) {
    var workId = String(value !== null && value !== void 0 ? value : '').trim();
    var normalized = workId.replace(/^\[|\]$/g, '').replace(/\s+/g, '').toLowerCase();
    if (!workId || normalized === '작업id' || normalized === 'workid' || normalized === 'undefined' || normalized === 'null') {
        return '반복작업';
    }
    return workId;
}
function normalizeRepeatIntervalMinutes(value) {
    var numericValue = Number(value);
    if (!Number.isFinite(numericValue)) {
        return 60;
    }
    return Math.min(525600, Math.max(1, Math.round(numericValue)));
}
function normalizeRepeatIntervalValue(value) {
    var numericValue = Number(value);
    if (!Number.isFinite(numericValue)) {
        return 60;
    }
    return Math.min(MAX_REPEAT_INTERVAL_SECONDS, Math.max(1, Math.round(numericValue)));
}
function normalizeRepeatIntervalSeconds(value) {
    var numericValue = Number(value);
    if (!Number.isFinite(numericValue)) {
        return DEFAULT_REPEAT_INTERVAL_SECONDS;
    }
    return Math.min(MAX_REPEAT_INTERVAL_SECONDS, Math.max(1, Math.round(numericValue)));
}
function normalizeRepeatIntervalUnit(value) {
    return repeatIntervalUnits.includes(value)
        ? value
        : 'minute';
}
function normalizeScheduleMode(value) {
    return scheduleModes.includes(value)
        ? value
        : 'interval';
}
function normalizeDailyRunTime(value) {
    return typeof value === 'string' && TIME_OF_DAY_PATTERN.test(value)
        ? value
        : DEFAULT_DAILY_RUN_TIME;
}
function normalizeOptionalTimeOfDay(value) {
    return typeof value === 'string' && TIME_OF_DAY_PATTERN.test(value) ? value : null;
}
function normalizeDateKey(value) {
    var trimmedValue = typeof value === 'string' ? value.trim() : '';
    return DATE_KEY_PATTERN.test(trimmedValue) ? trimmedValue : null;
}
function normalizeScheduleDateRanges(value) {
    if (!Array.isArray(value)) {
        return [];
    }
    var normalizedRanges = value
        .map(function (item) {
        return scheduleDateRangeSchema.safeParse({
            startDate: normalizeDateKey(item === null || item === void 0 ? void 0 : item.startDate),
            endDate: normalizeDateKey(item === null || item === void 0 ? void 0 : item.endDate),
        });
    })
        .filter(function (result) { return result.success; })
        .map(function (result) { return result.data; })
        .sort(function (left, right) {
        return left.startDate === right.startDate
            ? left.endDate.localeCompare(right.endDate)
            : left.startDate.localeCompare(right.startDate);
    });
    var uniqueRanges = [];
    var seen = new Set();
    for (var _i = 0, normalizedRanges_1 = normalizedRanges; _i < normalizedRanges_1.length; _i++) {
        var range = normalizedRanges_1[_i];
        var key = "".concat(range.startDate, ":").concat(range.endDate);
        if (seen.has(key)) {
            continue;
        }
        seen.add(key);
        uniqueRanges.push(range);
    }
    return uniqueRanges;
}
function normalizeScheduleWeekdays(value) {
    if (!Array.isArray(value)) {
        return [];
    }
    return Array.from(new Set(value
        .map(function (item) { return Number(item); })
        .filter(function (item) { return Number.isInteger(item) && item >= 0 && item <= 6; }))).sort(function (left, right) { return left - right; });
}
function parseScheduleWeekdays(value) {
    if (typeof value !== 'string' || !value.trim()) {
        return [];
    }
    try {
        return normalizeScheduleWeekdays(JSON.parse(value));
    }
    catch (_a) {
        return [];
    }
}
function stringifyScheduleWeekdays(value) {
    return JSON.stringify(normalizeScheduleWeekdays(value));
}
function parseScheduleDateRanges(value) {
    if (typeof value !== 'string' || !value.trim()) {
        return [];
    }
    try {
        return normalizeScheduleDateRanges(JSON.parse(value));
    }
    catch (_a) {
        return [];
    }
}
function stringifyScheduleDateRanges(value) {
    return JSON.stringify(normalizeScheduleDateRanges(value));
}
function normalizeScheduleTimeWindows(value) {
    var _a, _b;
    if (!Array.isArray(value)) {
        return [];
    }
    var normalizedWindows = value
        .map(function (item) {
        return scheduleTimeWindowSchema.safeParse({
            startTime: normalizeOptionalTimeOfDay(item === null || item === void 0 ? void 0 : item.startTime),
            endTime: normalizeOptionalTimeOfDay(item === null || item === void 0 ? void 0 : item.endTime),
        });
    })
        .filter(function (result) { return result.success; })
        .map(function (result) { return result.data; })
        .sort(function (left, right) {
        var _a, _b, _c, _d;
        var leftKey = "".concat((_a = left.startTime) !== null && _a !== void 0 ? _a : '', ":").concat((_b = left.endTime) !== null && _b !== void 0 ? _b : '');
        var rightKey = "".concat((_c = right.startTime) !== null && _c !== void 0 ? _c : '', ":").concat((_d = right.endTime) !== null && _d !== void 0 ? _d : '');
        return leftKey.localeCompare(rightKey);
    });
    var uniqueWindows = [];
    var seen = new Set();
    for (var _i = 0, normalizedWindows_1 = normalizedWindows; _i < normalizedWindows_1.length; _i++) {
        var window_1 = normalizedWindows_1[_i];
        var key = "".concat((_a = window_1.startTime) !== null && _a !== void 0 ? _a : '', ":").concat((_b = window_1.endTime) !== null && _b !== void 0 ? _b : '');
        if (seen.has(key)) {
            continue;
        }
        seen.add(key);
        uniqueWindows.push(window_1);
    }
    return uniqueWindows;
}
function parseScheduleTimeWindows(value) {
    if (typeof value !== 'string' || !value.trim()) {
        return [];
    }
    try {
        return normalizeScheduleTimeWindows(JSON.parse(value));
    }
    catch (_a) {
        return [];
    }
}
function stringifyScheduleTimeWindows(value) {
    return JSON.stringify(normalizeScheduleTimeWindows(value));
}
function toMinutesOfDay(value) {
    var _a = value.split(':').map(function (part) { return Number(part); }), hours = _a[0], minutes = _a[1];
    return hours * 60 + minutes;
}
function resolveScheduleTimeWindows(row) {
    var storedWindows = parseScheduleTimeWindows(row.repeat_windows_json);
    if (storedWindows.length) {
        return storedWindows;
    }
    var startTime = normalizeOptionalTimeOfDay(row.repeat_window_start_time);
    var endTime = normalizeOptionalTimeOfDay(row.repeat_window_end_time);
    return startTime || endTime
        ? [
            {
                startTime: startTime,
                endTime: endTime,
            },
        ]
        : [];
}
function buildKstDateTime(dateKey, timeOfDay) {
    return new Date("".concat(dateKey, "T").concat(timeOfDay, ":00+09:00"));
}
function resolveActiveRepeatWindow(row, now) {
    var nowParts = (0, worklog_automation_utils_js_1.getKstNowParts)(now);
    for (var _i = 0, _a = resolveScheduleTimeWindows(row); _i < _a.length; _i++) {
        var window_2 = _a[_i];
        var startMinutesOfDay = window_2.startTime ? toMinutesOfDay(window_2.startTime) : null;
        var endMinutesOfDay = window_2.endTime ? toMinutesOfDay(window_2.endTime) : null;
        var crossesMidnight = startMinutesOfDay !== null && endMinutesOfDay !== null && startMinutesOfDay > endMinutesOfDay;
        var isActive = startMinutesOfDay !== null && endMinutesOfDay !== null
            ? crossesMidnight
                ? nowParts.minutesOfDay >= startMinutesOfDay || nowParts.minutesOfDay <= endMinutesOfDay
                : nowParts.minutesOfDay >= startMinutesOfDay && nowParts.minutesOfDay <= endMinutesOfDay
            : startMinutesOfDay !== null
                ? nowParts.minutesOfDay >= startMinutesOfDay
                : endMinutesOfDay !== null
                    ? nowParts.minutesOfDay <= endMinutesOfDay
                    : false;
        if (!isActive) {
            continue;
        }
        var anchorDateKey = crossesMidnight && endMinutesOfDay !== null && nowParts.minutesOfDay <= endMinutesOfDay
            ? shiftKstDateKey(nowParts.dateKey, -1)
            : nowParts.dateKey;
        return {
            startTime: window_2.startTime,
            endTime: window_2.endTime,
            anchorDateKey: anchorDateKey,
        };
    }
    return null;
}
function shiftKstDateKey(dateKey, offsetDays) {
    var _a;
    var baseDate = buildKstDateTime(dateKey, '00:00');
    if (Number.isNaN(baseDate.getTime())) {
        return dateKey;
    }
    baseDate.setUTCDate(baseDate.getUTCDate() + offsetDays);
    return (_a = getKstDateKey(baseDate)) !== null && _a !== void 0 ? _a : dateKey;
}
function isDateWithinScheduleDateRanges(row, now) {
    var scheduleDateRanges = parseScheduleDateRanges(row.schedule_date_ranges_json);
    if (!scheduleDateRanges.length) {
        return true;
    }
    var dateKey = getKstDateKey(now);
    if (!dateKey) {
        return false;
    }
    return scheduleDateRanges.some(function (range) { return range.startDate <= dateKey && dateKey <= range.endDate; });
}
function getKstWeekday(now) {
    var dateKey = getKstDateKey(now);
    if (!dateKey) {
        return null;
    }
    var _a = dateKey.split('-').map(function (value) { return Number(value); }), year = _a[0], month = _a[1], day = _a[2];
    var date = new Date(Date.UTC(year, month - 1, day));
    if (Number.isNaN(date.getTime())) {
        return null;
    }
    return date.getUTCDay();
}
function isWithinScheduleWeekdays(row, now) {
    var scheduleWeekdays = parseScheduleWeekdays(row.schedule_weekdays_json);
    if (!scheduleWeekdays.length) {
        return true;
    }
    var weekday = getKstWeekday(now);
    return weekday !== null && scheduleWeekdays.includes(weekday);
}
function normalizeScheduleExecutionMode(value) {
    return scheduleExecutionModes.includes(value)
        ? value
        : 'codex';
}
function toRepeatIntervalMinutes(value, unit) {
    return Math.max(1, Math.ceil(toRepeatIntervalSeconds(value, unit) / 60));
}
function toRepeatIntervalSeconds(value, unit) {
    var repeatIntervalValue = normalizeRepeatIntervalValue(value);
    var repeatIntervalUnit = normalizeRepeatIntervalUnit(unit);
    if (repeatIntervalUnit === 'second') {
        return repeatIntervalValue;
    }
    if (repeatIntervalUnit === 'day') {
        return repeatIntervalValue * 24 * 60 * 60;
    }
    if (repeatIntervalUnit === 'week') {
        return repeatIntervalValue * 7 * 24 * 60 * 60;
    }
    if (repeatIntervalUnit === 'month') {
        return repeatIntervalValue * 30 * 24 * 60 * 60;
    }
    if (repeatIntervalUnit === 'hour') {
        return repeatIntervalValue * 60 * 60;
    }
    return repeatIntervalValue * 60;
}
function resolveStoredRepeatIntervalValue(row) {
    var _a, _b;
    return normalizeRepeatIntervalValue((_b = (_a = row.repeat_interval_value) !== null && _a !== void 0 ? _a : row.repeat_interval_minutes) !== null && _b !== void 0 ? _b : 60);
}
function resolveStoredRepeatIntervalUnit(row) {
    return normalizeRepeatIntervalUnit(row.repeat_interval_unit);
}
function resolveStoredRepeatIntervalSeconds(row) {
    return toRepeatIntervalSeconds(resolveStoredRepeatIntervalValue(row), resolveStoredRepeatIntervalUnit(row));
}
function resolveStoredRepeatIntervalMinutes(row) {
    return toRepeatIntervalMinutes(resolveStoredRepeatIntervalValue(row), resolveStoredRepeatIntervalUnit(row));
}
function normalizeBoolean(value, fallback) {
    if (typeof value === 'boolean') {
        return value;
    }
    if (value === 0 || value === '0' || value === 'false') {
        return false;
    }
    if (value === 1 || value === '1' || value === 'true') {
        return true;
    }
    return fallback;
}
function buildManagedServiceFailureSummary(result) {
    var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
    var summaryParts = [
        result.title ? "title=".concat(result.title) : null,
        "itemCount=".concat(Number((_a = result.itemCount) !== null && _a !== void 0 ? _a : 0)),
        "skipped=".concat(result.skipped ? 'true' : 'false'),
        "webOk=".concat(((_b = result.web) === null || _b === void 0 ? void 0 : _b.ok) ? 'true' : 'false'),
        "webSkipped=".concat(((_c = result.web) === null || _c === void 0 ? void 0 : _c.skipped) ? 'true' : 'false'),
        "webSent=".concat(Number((_e = (_d = result.web) === null || _d === void 0 ? void 0 : _d.sentCount) !== null && _e !== void 0 ? _e : 0)),
        "webFailed=".concat(Number((_g = (_f = result.web) === null || _f === void 0 ? void 0 : _f.failedCount) !== null && _g !== void 0 ? _g : 0)),
        ((_h = result.web) === null || _h === void 0 ? void 0 : _h.reason) ? "webReason=".concat(result.web.reason) : null,
        "iosOk=".concat(((_j = result.ios) === null || _j === void 0 ? void 0 : _j.ok) ? 'true' : 'false'),
        "iosSkipped=".concat(((_k = result.ios) === null || _k === void 0 ? void 0 : _k.skipped) ? 'true' : 'false'),
        ((_l = result.ios) === null || _l === void 0 ? void 0 : _l.reason) ? "iosReason=".concat(result.ios.reason) : null,
    ].filter(function (value) { return Boolean(value); });
    return summaryParts.join(', ');
}
function buildScheduledBoardPostTitle(row) {
    var _a, _b;
    var workId = normalizeScheduledWorkId(String((_a = row.work_id) !== null && _a !== void 0 ? _a : '반복작업'));
    var note = String((_b = row.note) !== null && _b !== void 0 ? _b : '')
        .split('\n')
        .map(function (line) { return line.trim(); })
        .find(Boolean);
    var title = note || workId;
    return title.length > 200 ? "".concat(title.slice(0, 197).trimEnd(), "...") : title;
}
function buildScheduledPlanWorkIdBase(row) {
    var _a;
    var workId = normalizeScheduledWorkId(String((_a = row.work_id) !== null && _a !== void 0 ? _a : '반복작업'));
    if (normalizeScheduleExecutionMode(row.execution_mode) !== 'managed-service') {
        return workId;
    }
    var scheduleId = Number(row.id);
    if (!Number.isInteger(scheduleId) || scheduleId <= 0) {
        return workId;
    }
    return normalizeScheduledWorkId("schedule-".concat(scheduleId, "-").concat(workId));
}
function shouldCreatePlanForScheduleExecution(row) {
    return normalizeScheduleExecutionMode(row.execution_mode) === 'managed-service';
}
function getKstDateKey(value) {
    if (!value) {
        return null;
    }
    var date = value instanceof Date ? value : new Date(String(value));
    if (Number.isNaN(date.getTime())) {
        return null;
    }
    return (0, worklog_automation_utils_js_1.getKstNowParts)(date).dateKey;
}
function isDailyScheduleDue(row, now) {
    var nowParts = (0, worklog_automation_utils_js_1.getKstNowParts)(now);
    var _a = normalizeDailyRunTime(row.daily_run_time).split(':').map(function (value) { return Number(value); }), hours = _a[0], minutes = _a[1];
    var scheduledMinutesOfDay = hours * 60 + minutes;
    return nowParts.minutesOfDay >= scheduledMinutesOfDay && getKstDateKey(row.last_registered_at) !== nowParts.dateKey;
}
function isIntervalScheduleDue(row, now) {
    var _a;
    var lastRegisteredAt = row.last_registered_at ? new Date(String(row.last_registered_at)) : null;
    var repeatIntervalSeconds = resolveStoredRepeatIntervalSeconds(row);
    if (!lastRegisteredAt || Number.isNaN(lastRegisteredAt.getTime())) {
        var activeWindow = resolveActiveRepeatWindow(row, now);
        if (activeWindow === null || activeWindow === void 0 ? void 0 : activeWindow.startTime) {
            var startAt = buildKstDateTime(activeWindow.anchorDateKey, activeWindow.startTime);
            if (!Number.isNaN(startAt.getTime())) {
                if (normalizeBoolean(row.immediate_run_enabled, true)) {
                    return now.getTime() >= startAt.getTime();
                }
                return now.getTime() >= startAt.getTime() + repeatIntervalSeconds * 1000;
            }
        }
    }
    var intervalBaseAt = lastRegisteredAt && !Number.isNaN(lastRegisteredAt.getTime())
        ? lastRegisteredAt
        : new Date(String((_a = row.created_at) !== null && _a !== void 0 ? _a : now.toISOString()));
    if (Number.isNaN(intervalBaseAt.getTime())) {
        return true;
    }
    return intervalBaseAt.getTime() <= now.getTime() - repeatIntervalSeconds * 1000;
}
function isWithinRepeatWindow(row, now) {
    var timeWindows = resolveScheduleTimeWindows(row);
    if (!timeWindows.length) {
        return true;
    }
    return resolveActiveRepeatWindow(row, now) !== null;
}
function isScheduleDue(row, now) {
    if (!isDateWithinScheduleDateRanges(row, now)) {
        return false;
    }
    var scheduleMode = normalizeScheduleMode(row.schedule_mode);
    if (scheduleMode === 'daily' && !isWithinScheduleWeekdays(row, now)) {
        return false;
    }
    if (scheduleMode === 'interval' && !isWithinScheduleWeekdays(row, now)) {
        return false;
    }
    if (scheduleMode === 'interval' && !isWithinRepeatWindow(row, now)) {
        return false;
    }
    if (!row.last_registered_at && normalizeBoolean(row.immediate_run_enabled, true)) {
        return true;
    }
    return scheduleMode === 'daily' ? isDailyScheduleDue(row, now) : isIntervalScheduleDue(row, now);
}
function isPlanScheduledTaskDue(row, now) {
    if (now === void 0) { now = new Date(); }
    return isScheduleDue(row, now);
}
function mapPlanScheduledTaskRow(row) {
    var _a, _b, _c, _d, _e;
    var repeatIntervalValue = resolveStoredRepeatIntervalValue(row);
    var repeatIntervalUnit = resolveStoredRepeatIntervalUnit(row);
    return {
        id: row.id,
        workId: row.work_id,
        note: row.note,
        automationType: (0, automation_type_config_service_js_1.resolveStoredAutomationTypeId)(row),
        automationContextIds: (0, automation_context_service_js_1.parseAutomationContextIds)(row.automation_context_ids_json),
        releaseTarget: row.release_target,
        jangsingProcessingRequired: Boolean((_a = row.jangsing_processing_required) !== null && _a !== void 0 ? _a : true),
        autoDeployToMain: Boolean((_b = row.auto_deploy_to_main) !== null && _b !== void 0 ? _b : true),
        suppressWebPush: Boolean((_c = row.suppress_web_push) !== null && _c !== void 0 ? _c : false),
        enabled: Boolean((_d = row.enabled) !== null && _d !== void 0 ? _d : true),
        immediateRunEnabled: normalizeBoolean(row.immediate_run_enabled, true),
        refreshContextSnapshotOnNextRun: normalizeBoolean(row.context_snapshot_refresh_requested, false),
        executionMode: normalizeScheduleExecutionMode(row.execution_mode),
        managedServiceKey: typeof row.managed_service_key === 'string' ? row.managed_service_key : null,
        managedServicePackageName: typeof row.managed_service_package_name === 'string' ? row.managed_service_package_name : null,
        managedServiceDirectory: typeof row.managed_service_directory === 'string' ? row.managed_service_directory : null,
        managedServiceManifestPath: typeof row.managed_service_manifest_path === 'string' ? row.managed_service_manifest_path : null,
        managedServiceGeneratedAt: (_e = row.managed_service_generated_at) !== null && _e !== void 0 ? _e : null,
        managedServiceGenerationPlanItemId: row.managed_service_generation_plan_item_id === null || row.managed_service_generation_plan_item_id === undefined
            ? null
            : Number(row.managed_service_generation_plan_item_id),
        managedServiceGenerationBoardPostId: row.managed_service_generation_board_post_id === null || row.managed_service_generation_board_post_id === undefined
            ? null
            : Number(row.managed_service_generation_board_post_id),
        recreateManagedServiceOnNextSave: normalizeBoolean(row.managed_service_recreate_requested, false),
        scheduleMode: normalizeScheduleMode(row.schedule_mode),
        repeatIntervalValue: repeatIntervalValue,
        repeatIntervalUnit: repeatIntervalUnit,
        repeatIntervalSeconds: resolveStoredRepeatIntervalSeconds(row),
        repeatIntervalMinutes: resolveStoredRepeatIntervalMinutes(row),
        dailyRunTime: normalizeDailyRunTime(row.daily_run_time),
        scheduleWeekdays: parseScheduleWeekdays(row.schedule_weekdays_json),
        scheduleDateRanges: parseScheduleDateRanges(row.schedule_date_ranges_json),
        repeatWindows: resolveScheduleTimeWindows(row),
        repeatWindowStartTime: normalizeOptionalTimeOfDay(row.repeat_window_start_time),
        repeatWindowEndTime: normalizeOptionalTimeOfDay(row.repeat_window_end_time),
        lastRegisteredAt: row.last_registered_at,
        createdAt: row.created_at,
        updatedAt: row.updated_at,
    };
}
function removeManagedServicePackage(scheduleId) {
    return __awaiter(this, void 0, void 0, function () {
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0: return [4 /*yield*/, (0, managed_schedule_service_js_1.removeManagedScheduleServiceArtifacts)(scheduleId)];
                case 1:
                    _a.sent();
                    return [2 /*return*/];
            }
        });
    });
}
function ensureManagedServicePackage(options) {
    return __awaiter(this, void 0, void 0, function () {
        var metadata;
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0:
                    metadata = (0, managed_schedule_service_js_1.buildManagedScheduleServiceMetadata)(options.scheduleId, options.workId);
                    return [4 /*yield*/, (0, managed_schedule_service_js_1.prepareManagedScheduleServiceDirectory)(options.scheduleId)];
                case 1:
                    _a.sent();
                    return [2 /*return*/, metadata];
            }
        });
    });
}
function buildScheduledManagedServicePlanWorkIdBase(row) {
    return buildScheduledPlanWorkIdBase(row);
}
function isManagedServiceGenerationPlanPending(row) {
    var _a, _b;
    var status = String((_a = row === null || row === void 0 ? void 0 : row.status) !== null && _a !== void 0 ? _a : '').trim();
    var workerStatus = String((_b = row === null || row === void 0 ? void 0 : row.worker_status) !== null && _b !== void 0 ? _b : '').trim();
    if (!status) {
        return false;
    }
    if (['완료', '릴리즈완료', '작업완료'].includes(status)) {
        return false;
    }
    if (['작업취소', '브랜치실패', '자동작업실패', 'release반영실패', 'main반영실패'].includes(workerStatus)) {
        return false;
    }
    return true;
}
function buildManagedServiceGenerationPlanNote(options) {
    var _a;
    var scheduleId = Number(options.row.id);
    var metadata = (0, managed_schedule_service_js_1.buildManagedScheduleServiceMetadata)(scheduleId, String((_a = options.row.work_id) !== null && _a !== void 0 ? _a : '반복작업'));
    var requestedReason = options.reason === 'requested' ? '사용자가 패키지 재처리를 요청함' : '실행 대상 서비스 패키지가 누락됨';
    return [
        '## 스케줄 서비스 패키지 생성 지시',
        "- \uB300\uC0C1 \uC2A4\uCF00\uC904 PK: ".concat(scheduleId),
        "- \uC791\uC5C5 ID base: ".concat(buildScheduledManagedServicePlanWorkIdBase(options.row)),
        "- \uC0DD\uC131 \uC0AC\uC720: ".concat(requestedReason),
        "- \uD328\uD0A4\uC9C0 \uB8E8\uD2B8: ".concat(metadata.relativeDirectory),
        "- \uC11C\uBE44\uC2A4 \uD0A4: ".concat(metadata.serviceKey),
        "- \uD328\uD0A4\uC9C0\uBA85: ".concat(metadata.packageName),
        '',
        '반드시 아래 파일을 위 패키지 루트에 직접 생성하거나 갱신하세요.',
        "- ".concat(metadata.readmePath),
        "- ".concat(metadata.sourcePath),
        "- ".concat(metadata.runtimePath),
        "- ".concat(metadata.manifestPath),
        '',
        '생성 규칙:',
        '- service.ts 와 service.mjs 는 둘 다 유지합니다.',
        '- service.mjs 는 스케줄 실행 시 직접 import 되어 `run(runtime)` 를 호출합니다.',
        '- README.md 에 서비스 목적, 실행 방식, 의존 경로, 검증 방법을 적습니다.',
        '- service-manifest.json 에 schedulePk, workId, serviceKey, packageName, relativeDirectory, sourcePath, runtimePath, readmePath, createdAt 를 기록합니다.',
        '- managed-service 같은 하위 임시 디렉터리를 다시 만들지 말고, 위 루트 경로만 사용합니다.',
        '- 실제 서비스 로직 요구사항은 아래 request/context 문서를 읽고 구현하세요. 본 자동화 메모 안에 원문 요구사항을 다시 복사하지 마세요.',
        '- generic placeholder 같은 빈 구현으로 남기지 마세요.',
        '',
        '참고 문서:',
        "- \uC694\uCCAD \uC815\uB9AC: ".concat(options.scheduleSnapshot.requestPath),
        "- \uCEE8\uD14D\uC2A4\uD2B8 \uC815\uB9AC: ".concat(options.scheduleSnapshot.contextPath),
        "- \uC2A4\uB0C5\uC0F7 manifest: ".concat(options.scheduleSnapshot.manifestPath),
        '',
        '검증 기준:',
        '- 생성 직후 위 네 파일이 모두 존재해야 합니다.',
        '- service.mjs 가 현재 저장소 코드 기준으로 바로 실행 가능한 상태여야 합니다.',
    ]
        .filter(Boolean)
        .join('\n')
        .trim();
}
function queueManagedServiceGenerationPlan(options) {
    return __awaiter(this, void 0, void 0, function () {
        var boardPost, automationReceipt, createdPlanItemId, updatedRows, createdPlan;
        var _a, _b, _c, _d, _e;
        return __generator(this, function (_f) {
            switch (_f.label) {
                case 0: return [4 /*yield*/, (0, board_service_js_1.createBoardPost)({
                        title: "[\uC2A4\uCF00\uC904 \uC11C\uBE44\uC2A4 \uC0DD\uC131] ".concat(buildScheduledBoardPostTitle(options.row)),
                        content: buildManagedServiceGenerationPlanNote({
                            row: options.row,
                            scheduleSnapshot: options.scheduleSnapshot,
                            reason: options.reason,
                        }),
                        attachments: [],
                        automationType: String((_b = (_a = options.row.automation_type_id) !== null && _a !== void 0 ? _a : options.row.automation_type) !== null && _b !== void 0 ? _b : 'none'),
                        automationContextIds: options.automationContextIds,
                        requestExecutionMode: 'all_at_once',
                        requestItems: [],
                    })];
                case 1:
                    boardPost = _f.sent();
                    return [4 /*yield*/, (0, board_service_js_1.receiveBoardPostAutomation)(Number(boardPost.id), {
                            planWorkIdBase: buildScheduledManagedServicePlanWorkIdBase(options.row),
                            planWorkIdSuffixLabel: 'service',
                            suppressWebPush: Boolean((_c = options.row.suppress_web_push) !== null && _c !== void 0 ? _c : false),
                        })];
                case 2:
                    automationReceipt = _f.sent();
                    createdPlanItemId = (_d = automationReceipt === null || automationReceipt === void 0 ? void 0 : automationReceipt.planItemIds[0]) !== null && _d !== void 0 ? _d : null;
                    if (!createdPlanItemId) {
                        throw new Error("Plan \uC2A4\uCF00\uC904 #".concat(options.row.id, " \uC11C\uBE44\uC2A4 \uD328\uD0A4\uC9C0 \uC790\uB3D9 \uC811\uC218\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4."));
                    }
                    return [4 /*yield*/, (0, client_js_1.db)(exports.PLAN_SCHEDULED_TASK_TABLE)
                            .where({ id: options.row.id })
                            .update({
                            managed_service_generation_board_post_id: Number(boardPost.id),
                            managed_service_generation_plan_item_id: Number(createdPlanItemId),
                            managed_service_recreate_requested: false,
                            updated_at: client_js_1.db.fn.now(),
                        })
                            .returning('*')];
                case 3:
                    updatedRows = _f.sent();
                    return [4 /*yield*/, (0, client_js_1.db)(plan_service_js_1.PLAN_TABLE).where({ id: createdPlanItemId }).first()];
                case 4:
                    createdPlan = _f.sent();
                    return [2 /*return*/, {
                            row: (_e = updatedRows[0]) !== null && _e !== void 0 ? _e : options.row,
                            createdPlan: createdPlan !== null && createdPlan !== void 0 ? createdPlan : null,
                            createdBoardPost: boardPost,
                        }];
            }
        });
    });
}
function ensureManagedServiceExecutionReady(options) {
    return __awaiter(this, void 0, void 0, function () {
        var row, scheduleSnapshot, automationContextIds, recreateRequested, packageExists, existingPlanId, existingPlan, _a, updatedRows, queued;
        var _b, _c, _d, _e, _f, _g, _h;
        return __generator(this, function (_j) {
            switch (_j.label) {
                case 0:
                    row = options.row, scheduleSnapshot = options.scheduleSnapshot, automationContextIds = options.automationContextIds;
                    if (normalizeScheduleExecutionMode(row.execution_mode) !== 'managed-service') {
                        return [2 /*return*/, {
                                row: row,
                                ready: true,
                                generationTriggered: false,
                                reason: null,
                                createdPlan: null,
                                createdBoardPosts: [],
                            }];
                    }
                    recreateRequested = normalizeBoolean(row.managed_service_recreate_requested, false);
                    return [4 /*yield*/, (0, managed_schedule_service_js_1.hasManagedScheduleServicePackage)(typeof row.managed_service_directory === 'string' ? row.managed_service_directory : null)];
                case 1:
                    packageExists = _j.sent();
                    if (packageExists && !recreateRequested) {
                        return [2 /*return*/, {
                                row: row,
                                ready: true,
                                generationTriggered: false,
                                reason: null,
                                createdPlan: null,
                                createdBoardPosts: [],
                            }];
                    }
                    existingPlanId = Number((_b = row.managed_service_generation_plan_item_id) !== null && _b !== void 0 ? _b : 0);
                    if (!(existingPlanId > 0)) return [3 /*break*/, 3];
                    return [4 /*yield*/, (0, client_js_1.db)(plan_service_js_1.PLAN_TABLE).where({ id: existingPlanId }).first()];
                case 2:
                    _a = _j.sent();
                    return [3 /*break*/, 4];
                case 3:
                    _a = null;
                    _j.label = 4;
                case 4:
                    existingPlan = _a;
                    if (!(packageExists && existingPlan && !recreateRequested)) return [3 /*break*/, 6];
                    return [4 /*yield*/, (0, client_js_1.db)(exports.PLAN_SCHEDULED_TASK_TABLE)
                            .where({ id: row.id })
                            .update({
                            managed_service_recreate_requested: false,
                            managed_service_generated_at: client_js_1.db.fn.now(),
                            updated_at: client_js_1.db.fn.now(),
                        })
                            .returning('*')];
                case 5:
                    updatedRows = _j.sent();
                    return [2 /*return*/, {
                            row: (_c = updatedRows[0]) !== null && _c !== void 0 ? _c : row,
                            ready: true,
                            generationTriggered: false,
                            reason: null,
                            createdPlan: null,
                            createdBoardPosts: [],
                        }];
                case 6:
                    if (existingPlan && isManagedServiceGenerationPlanPending(existingPlan)) {
                        return [2 /*return*/, {
                                row: row,
                                ready: false,
                                generationTriggered: false,
                                reason: recreateRequested ? 'requested' : 'missing',
                                createdPlan: existingPlan,
                                createdBoardPosts: [],
                            }];
                    }
                    return [4 /*yield*/, removeManagedServicePackage(Number(row.id))];
                case 7:
                    _j.sent();
                    return [4 /*yield*/, ensureManagedServicePackage({
                            scheduleId: Number(row.id),
                            workId: String((_d = row.work_id) !== null && _d !== void 0 ? _d : '반복작업'),
                            note: String((_e = row.note) !== null && _e !== void 0 ? _e : ''),
                            releaseTarget: String((_f = row.release_target) !== null && _f !== void 0 ? _f : 'release'),
                            automationType: String((_h = (_g = row.automation_type_id) !== null && _g !== void 0 ? _g : row.automation_type) !== null && _h !== void 0 ? _h : 'none'),
                        })];
                case 8:
                    _j.sent();
                    return [4 /*yield*/, queueManagedServiceGenerationPlan({
                            row: row,
                            scheduleSnapshot: scheduleSnapshot,
                            automationContextIds: automationContextIds,
                            reason: recreateRequested ? 'requested' : 'missing',
                        })];
                case 9:
                    queued = _j.sent();
                    return [2 /*return*/, {
                            row: queued.row,
                            ready: false,
                            generationTriggered: true,
                            reason: recreateRequested ? 'requested' : 'missing',
                            createdPlan: queued.createdPlan,
                            createdBoardPosts: [queued.createdBoardPost],
                        }];
            }
        });
    });
}
function ensurePlanScheduledTaskColumn(columnName, addColumn) {
    return __awaiter(this, void 0, void 0, function () {
        var hasColumn;
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0: return [4 /*yield*/, client_js_1.db.schema.hasColumn(exports.PLAN_SCHEDULED_TASK_TABLE, columnName)];
                case 1:
                    hasColumn = _a.sent();
                    if (hasColumn) {
                        return [2 /*return*/];
                    }
                    return [4 /*yield*/, client_js_1.db.schema.alterTable(exports.PLAN_SCHEDULED_TASK_TABLE, function (table) {
                            addColumn(table);
                        })];
                case 2:
                    _a.sent();
                    return [2 /*return*/];
            }
        });
    });
}
function ensurePlanScheduledTaskTable() {
    return __awaiter(this, void 0, void 0, function () {
        var exists, existingWindowRows, _i, existingWindowRows_1, row, normalizedWindows, currentWindows, existingRows, _a, existingRows_1, row, repeatIntervalSeconds, repeatIntervalMinutes, currentSeconds, currentMinutes;
        var _b, _c;
        return __generator(this, function (_d) {
            switch (_d.label) {
                case 0: return [4 /*yield*/, client_js_1.db.schema.hasTable(exports.PLAN_SCHEDULED_TASK_TABLE)];
                case 1:
                    exists = _d.sent();
                    if (!!exists) return [3 /*break*/, 3];
                    return [4 /*yield*/, client_js_1.db.schema.createTable(exports.PLAN_SCHEDULED_TASK_TABLE, function (table) {
                            table.increments('id').primary();
                            table.string('work_id', 120).notNullable().defaultTo('반복작업');
                            table.text('note').notNullable().defaultTo('');
                            table.string('automation_type', 40).notNullable().defaultTo('none');
                            table.string('automation_type_id', 120).nullable();
                            table.text('automation_context_ids_json').notNullable().defaultTo('[]');
                            table.string('release_target', 120).notNullable().defaultTo('release');
                            table.boolean('jangsing_processing_required').notNullable().defaultTo(true);
                            table.boolean('auto_deploy_to_main').notNullable().defaultTo(true);
                            table.boolean('suppress_web_push').notNullable().defaultTo(false);
                            table.boolean('enabled').notNullable().defaultTo(true);
                            table.boolean('immediate_run_enabled').notNullable().defaultTo(true);
                            table.boolean('context_snapshot_refresh_requested').notNullable().defaultTo(false);
                            table.string('execution_mode', 40).notNullable().defaultTo('codex');
                            table.string('managed_service_key', 160).nullable();
                            table.string('managed_service_package_name', 200).nullable();
                            table.text('managed_service_directory').nullable();
                            table.text('managed_service_manifest_path').nullable();
                            table.timestamp('managed_service_generated_at', { useTz: true }).nullable();
                            table.integer('managed_service_generation_plan_item_id').nullable();
                            table.integer('managed_service_generation_board_post_id').nullable();
                            table.boolean('managed_service_recreate_requested').notNullable().defaultTo(false);
                            table.string('schedule_mode', 20).notNullable().defaultTo('interval');
                            table.integer('repeat_interval_value').notNullable().defaultTo(60);
                            table.string('repeat_interval_unit', 20).notNullable().defaultTo('minute');
                            table.integer('repeat_interval_minutes').notNullable().defaultTo(60);
                            table.integer('repeat_interval_seconds').notNullable().defaultTo(DEFAULT_REPEAT_INTERVAL_SECONDS);
                            table.string('daily_run_time', 5).notNullable().defaultTo(DEFAULT_DAILY_RUN_TIME);
                            table.text('schedule_weekdays_json').notNullable().defaultTo('[]');
                            table.text('schedule_date_ranges_json').notNullable().defaultTo('[]');
                            table.text('repeat_windows_json').notNullable().defaultTo('[]');
                            table.string('repeat_window_start_time', 5).nullable();
                            table.string('repeat_window_end_time', 5).nullable();
                            table.timestamp('last_registered_at', { useTz: true }).nullable();
                            table.timestamp('context_snapshot_generated_at', { useTz: true }).nullable();
                            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 2:
                    _d.sent();
                    return [2 /*return*/];
                case 3: return [4 /*yield*/, ensurePlanScheduledTaskColumn('release_target', function (table) {
                        table.string('release_target', 120).notNullable().defaultTo('release');
                    })];
                case 4:
                    _d.sent();
                    return [4 /*yield*/, ensurePlanScheduledTaskColumn('automation_type', function (table) {
                            table.string('automation_type', 40).notNullable().defaultTo('none');
                        })];
                case 5:
                    _d.sent();
                    return [4 /*yield*/, ensurePlanScheduledTaskColumn('automation_type_id', function (table) {
                            table.string('automation_type_id', 120).nullable();
                        })];
                case 6:
                    _d.sent();
                    return [4 /*yield*/, ensurePlanScheduledTaskColumn('automation_context_ids_json', function (table) {
                            table.text('automation_context_ids_json').notNullable().defaultTo('[]');
                        })];
                case 7:
                    _d.sent();
                    return [4 /*yield*/, ensurePlanScheduledTaskColumn('jangsing_processing_required', function (table) {
                            table.boolean('jangsing_processing_required').notNullable().defaultTo(true);
                        })];
                case 8:
                    _d.sent();
                    return [4 /*yield*/, ensurePlanScheduledTaskColumn('auto_deploy_to_main', function (table) {
                            table.boolean('auto_deploy_to_main').notNullable().defaultTo(true);
                        })];
                case 9:
                    _d.sent();
                    return [4 /*yield*/, ensurePlanScheduledTaskColumn('suppress_web_push', function (table) {
                            table.boolean('suppress_web_push').notNullable().defaultTo(false);
                        })];
                case 10:
                    _d.sent();
                    return [4 /*yield*/, ensurePlanScheduledTaskColumn('enabled', function (table) {
                            table.boolean('enabled').notNullable().defaultTo(true);
                        })];
                case 11:
                    _d.sent();
                    return [4 /*yield*/, ensurePlanScheduledTaskColumn('immediate_run_enabled', function (table) {
                            table.boolean('immediate_run_enabled').notNullable().defaultTo(true);
                        })];
                case 12:
                    _d.sent();
                    return [4 /*yield*/, ensurePlanScheduledTaskColumn('context_snapshot_refresh_requested', function (table) {
                            table.boolean('context_snapshot_refresh_requested').notNullable().defaultTo(false);
                        })];
                case 13:
                    _d.sent();
                    return [4 /*yield*/, ensurePlanScheduledTaskColumn('execution_mode', function (table) {
                            table.string('execution_mode', 40).notNullable().defaultTo('codex');
                        })];
                case 14:
                    _d.sent();
                    return [4 /*yield*/, ensurePlanScheduledTaskColumn('managed_service_key', function (table) {
                            table.string('managed_service_key', 160).nullable();
                        })];
                case 15:
                    _d.sent();
                    return [4 /*yield*/, ensurePlanScheduledTaskColumn('managed_service_package_name', function (table) {
                            table.string('managed_service_package_name', 200).nullable();
                        })];
                case 16:
                    _d.sent();
                    return [4 /*yield*/, ensurePlanScheduledTaskColumn('managed_service_directory', function (table) {
                            table.text('managed_service_directory').nullable();
                        })];
                case 17:
                    _d.sent();
                    return [4 /*yield*/, ensurePlanScheduledTaskColumn('managed_service_manifest_path', function (table) {
                            table.text('managed_service_manifest_path').nullable();
                        })];
                case 18:
                    _d.sent();
                    return [4 /*yield*/, ensurePlanScheduledTaskColumn('managed_service_generated_at', function (table) {
                            table.timestamp('managed_service_generated_at', { useTz: true }).nullable();
                        })];
                case 19:
                    _d.sent();
                    return [4 /*yield*/, ensurePlanScheduledTaskColumn('managed_service_generation_plan_item_id', function (table) {
                            table.integer('managed_service_generation_plan_item_id').nullable();
                        })];
                case 20:
                    _d.sent();
                    return [4 /*yield*/, ensurePlanScheduledTaskColumn('managed_service_generation_board_post_id', function (table) {
                            table.integer('managed_service_generation_board_post_id').nullable();
                        })];
                case 21:
                    _d.sent();
                    return [4 /*yield*/, ensurePlanScheduledTaskColumn('managed_service_recreate_requested', function (table) {
                            table.boolean('managed_service_recreate_requested').notNullable().defaultTo(false);
                        })];
                case 22:
                    _d.sent();
                    return [4 /*yield*/, ensurePlanScheduledTaskColumn('schedule_mode', function (table) {
                            table.string('schedule_mode', 20).notNullable().defaultTo('interval');
                        })];
                case 23:
                    _d.sent();
                    return [4 /*yield*/, ensurePlanScheduledTaskColumn('repeat_interval_value', function (table) {
                            table.integer('repeat_interval_value').notNullable().defaultTo(60);
                        })];
                case 24:
                    _d.sent();
                    return [4 /*yield*/, ensurePlanScheduledTaskColumn('repeat_interval_unit', function (table) {
                            table.string('repeat_interval_unit', 20).notNullable().defaultTo('minute');
                        })];
                case 25:
                    _d.sent();
                    return [4 /*yield*/, ensurePlanScheduledTaskColumn('repeat_interval_minutes', function (table) {
                            table.integer('repeat_interval_minutes').notNullable().defaultTo(60);
                        })];
                case 26:
                    _d.sent();
                    return [4 /*yield*/, ensurePlanScheduledTaskColumn('repeat_interval_seconds', function (table) {
                            table.integer('repeat_interval_seconds').notNullable().defaultTo(DEFAULT_REPEAT_INTERVAL_SECONDS);
                        })];
                case 27:
                    _d.sent();
                    return [4 /*yield*/, ensurePlanScheduledTaskColumn('daily_run_time', function (table) {
                            table.string('daily_run_time', 5).notNullable().defaultTo(DEFAULT_DAILY_RUN_TIME);
                        })];
                case 28:
                    _d.sent();
                    return [4 /*yield*/, ensurePlanScheduledTaskColumn('schedule_weekdays_json', function (table) {
                            table.text('schedule_weekdays_json').notNullable().defaultTo('[]');
                        })];
                case 29:
                    _d.sent();
                    return [4 /*yield*/, ensurePlanScheduledTaskColumn('schedule_date_ranges_json', function (table) {
                            table.text('schedule_date_ranges_json').notNullable().defaultTo('[]');
                        })];
                case 30:
                    _d.sent();
                    return [4 /*yield*/, ensurePlanScheduledTaskColumn('repeat_windows_json', function (table) {
                            table.text('repeat_windows_json').notNullable().defaultTo('[]');
                        })];
                case 31:
                    _d.sent();
                    return [4 /*yield*/, ensurePlanScheduledTaskColumn('repeat_window_start_time', function (table) {
                            table.string('repeat_window_start_time', 5).nullable();
                        })];
                case 32:
                    _d.sent();
                    return [4 /*yield*/, ensurePlanScheduledTaskColumn('repeat_window_end_time', function (table) {
                            table.string('repeat_window_end_time', 5).nullable();
                        })];
                case 33:
                    _d.sent();
                    return [4 /*yield*/, ensurePlanScheduledTaskColumn('last_registered_at', function (table) {
                            table.timestamp('last_registered_at', { useTz: true }).nullable();
                        })];
                case 34:
                    _d.sent();
                    return [4 /*yield*/, ensurePlanScheduledTaskColumn('context_snapshot_generated_at', function (table) {
                            table.timestamp('context_snapshot_generated_at', { useTz: true }).nullable();
                        })];
                case 35:
                    _d.sent();
                    return [4 /*yield*/, ensurePlanScheduledTaskColumn('created_at', function (table) {
                            table.timestamp('created_at', { useTz: true }).notNullable().defaultTo(client_js_1.db.fn.now());
                        })];
                case 36:
                    _d.sent();
                    return [4 /*yield*/, ensurePlanScheduledTaskColumn('updated_at', function (table) {
                            table.timestamp('updated_at', { useTz: true }).notNullable().defaultTo(client_js_1.db.fn.now());
                        })];
                case 37:
                    _d.sent();
                    return [4 /*yield*/, (0, client_js_1.db)(exports.PLAN_SCHEDULED_TASK_TABLE)
                            .where({ automation_type: 'plan_registration' })
                            .update({ automation_type: 'plan' })];
                case 38:
                    _d.sent();
                    return [4 /*yield*/, (0, client_js_1.db)(exports.PLAN_SCHEDULED_TASK_TABLE)
                            .where({ automation_type: 'general_development' })
                            .update({ automation_type: 'auto_worker' })];
                case 39:
                    _d.sent();
                    return [4 /*yield*/, (0, client_js_1.db)(exports.PLAN_SCHEDULED_TASK_TABLE)
                            .whereNull('automation_type_id')
                            .update({
                            automation_type_id: client_js_1.db.raw('automation_type'),
                        })];
                case 40:
                    _d.sent();
                    return [4 /*yield*/, (0, client_js_1.db)(exports.PLAN_SCHEDULED_TASK_TABLE)
                            .where({ repeat_interval_unit: 'minute' })
                            .update({
                            repeat_interval_value: client_js_1.db.raw('repeat_interval_minutes'),
                        })];
                case 41:
                    _d.sent();
                    return [4 /*yield*/, (0, client_js_1.db)(exports.PLAN_SCHEDULED_TASK_TABLE)
                            .whereNull('repeat_interval_seconds')
                            .update({
                            repeat_interval_seconds: client_js_1.db.raw('repeat_interval_minutes * 60'),
                        })];
                case 42:
                    _d.sent();
                    return [4 /*yield*/, (0, client_js_1.db)(exports.PLAN_SCHEDULED_TASK_TABLE)
                            .whereNull('suppress_web_push')
                            .update({
                            suppress_web_push: false,
                        })];
                case 43:
                    _d.sent();
                    return [4 /*yield*/, (0, client_js_1.db)(exports.PLAN_SCHEDULED_TASK_TABLE).select('id', 'repeat_windows_json', 'repeat_window_start_time', 'repeat_window_end_time')];
                case 44:
                    existingWindowRows = _d.sent();
                    _i = 0, existingWindowRows_1 = existingWindowRows;
                    _d.label = 45;
                case 45:
                    if (!(_i < existingWindowRows_1.length)) return [3 /*break*/, 48];
                    row = existingWindowRows_1[_i];
                    normalizedWindows = resolveScheduleTimeWindows(row);
                    currentWindows = parseScheduleTimeWindows(row.repeat_windows_json);
                    if (JSON.stringify(currentWindows) === JSON.stringify(normalizedWindows)) {
                        return [3 /*break*/, 47];
                    }
                    return [4 /*yield*/, (0, client_js_1.db)(exports.PLAN_SCHEDULED_TASK_TABLE)
                            .where({ id: row.id })
                            .update({
                            repeat_windows_json: stringifyScheduleTimeWindows(normalizedWindows),
                        })];
                case 46:
                    _d.sent();
                    _d.label = 47;
                case 47:
                    _i++;
                    return [3 /*break*/, 45];
                case 48: return [4 /*yield*/, (0, client_js_1.db)(exports.PLAN_SCHEDULED_TASK_TABLE).select('id', 'repeat_interval_value', 'repeat_interval_unit', 'repeat_interval_minutes', 'repeat_interval_seconds')];
                case 49:
                    existingRows = _d.sent();
                    _a = 0, existingRows_1 = existingRows;
                    _d.label = 50;
                case 50:
                    if (!(_a < existingRows_1.length)) return [3 /*break*/, 53];
                    row = existingRows_1[_a];
                    repeatIntervalSeconds = resolveStoredRepeatIntervalSeconds(row);
                    repeatIntervalMinutes = resolveStoredRepeatIntervalMinutes(row);
                    currentSeconds = normalizeRepeatIntervalSeconds((_b = row.repeat_interval_seconds) !== null && _b !== void 0 ? _b : repeatIntervalSeconds);
                    currentMinutes = normalizeRepeatIntervalMinutes((_c = row.repeat_interval_minutes) !== null && _c !== void 0 ? _c : repeatIntervalMinutes);
                    if (currentSeconds === repeatIntervalSeconds && currentMinutes === repeatIntervalMinutes) {
                        return [3 /*break*/, 52];
                    }
                    return [4 /*yield*/, (0, client_js_1.db)(exports.PLAN_SCHEDULED_TASK_TABLE)
                            .where({ id: row.id })
                            .update({
                            repeat_interval_seconds: repeatIntervalSeconds,
                            repeat_interval_minutes: repeatIntervalMinutes,
                        })];
                case 51:
                    _d.sent();
                    _d.label = 52;
                case 52:
                    _a++;
                    return [3 /*break*/, 50];
                case 53: return [2 /*return*/];
            }
        });
    });
}
function listPlanScheduledTasks() {
    return __awaiter(this, void 0, void 0, function () {
        var rows;
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0: return [4 /*yield*/, ensurePlanScheduledTaskTable()];
                case 1:
                    _a.sent();
                    return [4 /*yield*/, (0, client_js_1.db)(exports.PLAN_SCHEDULED_TASK_TABLE).select('*').orderBy('id', 'desc')];
                case 2:
                    rows = _a.sent();
                    return [4 /*yield*/, Promise.all(rows.map(function (row) { return syncManagedServiceGenerationCompletionForScheduleRow(row); }))];
                case 3: return [2 /*return*/, _a.sent()];
            }
        });
    });
}
function getPlanScheduledTaskById(id) {
    return __awaiter(this, void 0, void 0, function () {
        var row;
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0: return [4 /*yield*/, ensurePlanScheduledTaskTable()];
                case 1:
                    _a.sent();
                    return [4 /*yield*/, (0, client_js_1.db)(exports.PLAN_SCHEDULED_TASK_TABLE).where({ id: id }).first()];
                case 2:
                    row = _a.sent();
                    return [4 /*yield*/, (row ? syncManagedServiceGenerationCompletionForScheduleRow(row) : null)];
                case 3: return [2 /*return*/, _a.sent()];
            }
        });
    });
}
function syncManagedServiceGenerationCompletionForScheduleRow(row) {
    return __awaiter(this, void 0, void 0, function () {
        var generationPlanItemId, packageExists, generationPlan, generationPlanStatus, generationPlanWorkerStatus, isCompletedPlan, updatedRows;
        var _a;
        return __generator(this, function (_b) {
            switch (_b.label) {
                case 0:
                    if (normalizeScheduleExecutionMode(row.execution_mode) !== 'managed-service') {
                        return [2 /*return*/, row];
                    }
                    generationPlanItemId = Number((_a = row.managed_service_generation_plan_item_id) !== null && _a !== void 0 ? _a : 0);
                    if (generationPlanItemId <= 0) {
                        return [2 /*return*/, row];
                    }
                    return [4 /*yield*/, (0, managed_schedule_service_js_1.hasManagedScheduleServicePackage)(typeof row.managed_service_directory === 'string' ? row.managed_service_directory : null)];
                case 1:
                    packageExists = _b.sent();
                    if (!packageExists) {
                        return [2 /*return*/, row];
                    }
                    return [4 /*yield*/, (0, client_js_1.db)(plan_service_js_1.PLAN_TABLE)
                            .select('id', 'status', 'worker_status')
                            .where({ id: generationPlanItemId })
                            .first()];
                case 2:
                    generationPlan = _b.sent();
                    generationPlanStatus = String((generationPlan === null || generationPlan === void 0 ? void 0 : generationPlan.status) !== null && (generationPlan === null || generationPlan === void 0 ? void 0 : generationPlan.status) !== void 0 ? generationPlan.status : '').trim();
                    generationPlanWorkerStatus = String((generationPlan === null || generationPlan === void 0 ? void 0 : generationPlan.worker_status) !== null && (generationPlan === null || generationPlan === void 0 ? void 0 : generationPlan.worker_status) !== void 0 ? generationPlan.worker_status : '').trim();
                    isCompletedPlan = Boolean(generationPlan)
                        && ['완료', '작업완료', '릴리즈완료'].includes(generationPlanStatus)
                        && !['브랜치실패', '자동작업실패', 'release반영실패', 'main반영실패'].includes(generationPlanWorkerStatus);
                    if (!isCompletedPlan) {
                        return [2 /*return*/, row];
                    }
                    if (row.managed_service_generated_at && !normalizeBoolean(row.managed_service_recreate_requested, false)) {
                        return [2 /*return*/, row];
                    }
                    return [4 /*yield*/, (0, client_js_1.db)(exports.PLAN_SCHEDULED_TASK_TABLE)
                            .where({ id: row.id })
                            .update({
                            managed_service_generated_at: client_js_1.db.fn.now(),
                            managed_service_recreate_requested: false,
                            updated_at: client_js_1.db.fn.now(),
                        })
                            .returning('*')];
                case 3:
                    updatedRows = _b.sent();
                    return [2 /*return*/, updatedRows[0] || row];
            }
        });
    });
}
function syncManagedServiceGenerationCompletion(planItemId) {
    return __awaiter(this, void 0, void 0, function () {
        var rows, syncedRows;
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0: return [4 /*yield*/, ensurePlanScheduledTaskTable()];
                case 1:
                    _a.sent();
                    return [4 /*yield*/, (0, client_js_1.db)(exports.PLAN_SCHEDULED_TASK_TABLE)
                            .select('*')
                            .where({ managed_service_generation_plan_item_id: planItemId })];
                case 2:
                    rows = _a.sent();
                    return [4 /*yield*/, Promise.all(rows.map(function (row) { return syncManagedServiceGenerationCompletionForScheduleRow(row); }))];
                case 3:
                    syncedRows = _a.sent();
                    return [2 /*return*/, syncedRows.filter(function (row) { return Boolean(row.managed_service_generated_at); })];
            }
        });
    });
}
function createPlanScheduledTask(payload) {
    return __awaiter(this, void 0, void 0, function () {
        var scheduleMode, repeatIntervalValue, repeatIntervalUnit, automationType, executionMode, repeatWindows, firstRepeatWindow, shouldAcknowledgeManagedServiceRefreshOnNextRun, rows, row, managedService, updatedRows;
        var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
        return __generator(this, function (_o) {
            switch (_o.label) {
                case 0: return [4 /*yield*/, ensurePlanScheduledTaskTable()];
                case 1:
                    _o.sent();
                    scheduleMode = normalizeScheduleMode(payload.scheduleMode);
                    repeatIntervalValue = normalizeRepeatIntervalValue(payload.repeatIntervalValue);
                    repeatIntervalUnit = normalizeRepeatIntervalUnit(payload.repeatIntervalUnit);
                    return [4 /*yield*/, (0, automation_type_config_service_js_1.resolveAutomationType)(payload.automationType)];
                case 2:
                    automationType = _o.sent();
                    executionMode = normalizeScheduleExecutionMode(payload.executionMode);
                    repeatWindows = normalizeScheduleTimeWindows(payload.repeatWindows);
                    firstRepeatWindow = (_a = repeatWindows[0]) !== null && _a !== void 0 ? _a : null;
                    shouldAcknowledgeManagedServiceRefreshOnNextRun = executionMode === 'managed-service' && Boolean(payload.recreateManagedServiceOnNextSave);
                    return [4 /*yield*/, (0, client_js_1.db)(exports.PLAN_SCHEDULED_TASK_TABLE)
                            .insert({
                            work_id: normalizeScheduledWorkId(payload.workId),
                            note: payload.note,
                            automation_type: automationType.behaviorType,
                            automation_type_id: automationType.id,
                            automation_context_ids_json: (0, automation_context_service_js_1.stringifyAutomationContextIds)(payload.automationContextIds),
                            release_target: payload.releaseTarget,
                            jangsing_processing_required: payload.jangsingProcessingRequired,
                            auto_deploy_to_main: payload.autoDeployToMain,
                            suppress_web_push: payload.suppressWebPush,
                            enabled: payload.enabled,
                            immediate_run_enabled: payload.immediateRunEnabled,
                            context_snapshot_refresh_requested: payload.refreshContextSnapshotOnNextRun,
                            execution_mode: executionMode,
                            managed_service_recreate_requested: shouldAcknowledgeManagedServiceRefreshOnNextRun,
                            schedule_mode: scheduleMode,
                            repeat_interval_value: repeatIntervalValue,
                            repeat_interval_unit: repeatIntervalUnit,
                            repeat_interval_seconds: toRepeatIntervalSeconds(repeatIntervalValue, repeatIntervalUnit),
                            repeat_interval_minutes: toRepeatIntervalMinutes(repeatIntervalValue, repeatIntervalUnit),
                            daily_run_time: normalizeDailyRunTime(payload.dailyRunTime),
                            schedule_weekdays_json: stringifyScheduleWeekdays(payload.scheduleWeekdays),
                            schedule_date_ranges_json: stringifyScheduleDateRanges(payload.scheduleDateRanges),
                            repeat_windows_json: stringifyScheduleTimeWindows(repeatWindows),
                            repeat_window_start_time: (_b = firstRepeatWindow === null || firstRepeatWindow === void 0 ? void 0 : firstRepeatWindow.startTime) !== null && _b !== void 0 ? _b : null,
                            repeat_window_end_time: (_c = firstRepeatWindow === null || firstRepeatWindow === void 0 ? void 0 : firstRepeatWindow.endTime) !== null && _c !== void 0 ? _c : null,
                            updated_at: client_js_1.db.fn.now(),
                        })
                            .returning('*')];
                case 3:
                    rows = _o.sent();
                    row = rows[0];
                    if (!(executionMode === 'managed-service' && (row === null || row === void 0 ? void 0 : row.id))) return [3 /*break*/, 6];
                    return [4 /*yield*/, ensureManagedServicePackage({
                            scheduleId: Number(row.id),
                            workId: String((_e = (_d = row.work_id) !== null && _d !== void 0 ? _d : payload.workId) !== null && _e !== void 0 ? _e : '반복작업'),
                            note: String((_g = (_f = row.note) !== null && _f !== void 0 ? _f : payload.note) !== null && _g !== void 0 ? _g : ''),
                            releaseTarget: String((_j = (_h = row.release_target) !== null && _h !== void 0 ? _h : payload.releaseTarget) !== null && _j !== void 0 ? _j : 'release'),
                            automationType: String((_l = (_k = row.automation_type_id) !== null && _k !== void 0 ? _k : row.automation_type) !== null && _l !== void 0 ? _l : automationType.id),
                        })];
                case 4:
                    managedService = _o.sent();
                    return [4 /*yield*/, (0, client_js_1.db)(exports.PLAN_SCHEDULED_TASK_TABLE)
                            .where({ id: row.id })
                            .update({
                            managed_service_key: managedService.serviceKey,
                            managed_service_package_name: managedService.packageName,
                            managed_service_directory: managedService.relativeDirectory,
                            managed_service_manifest_path: managedService.manifestPath,
                            managed_service_generated_at: null,
                            managed_service_generation_plan_item_id: null,
                            managed_service_generation_board_post_id: null,
                            managed_service_recreate_requested: shouldAcknowledgeManagedServiceRefreshOnNextRun,
                            updated_at: client_js_1.db.fn.now(),
                        })
                            .returning('*')];
                case 5:
                    updatedRows = _o.sent();
                    row = (_m = updatedRows[0]) !== null && _m !== void 0 ? _m : row;
                    _o.label = 6;
                case 6: return [2 /*return*/, row];
            }
        });
    });
}
function updatePlanScheduledTask(id, payload) {
    return __awaiter(this, void 0, void 0, function () {
        var currentRow, scheduleMode, repeatIntervalValue, repeatIntervalUnit, executionMode, automationType, repeatWindows, firstRepeatWindow, shouldRecreateManagedService, rows, row, updatedRows, managedService, updatedRows;
        var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24;
        return __generator(this, function (_25) {
            switch (_25.label) {
                case 0: return [4 /*yield*/, ensurePlanScheduledTaskTable()];
                case 1:
                    _25.sent();
                    return [4 /*yield*/, (0, client_js_1.db)(exports.PLAN_SCHEDULED_TASK_TABLE).where({ id: id }).first()];
                case 2:
                    currentRow = _25.sent();
                    if (!currentRow) {
                        return [2 /*return*/, null];
                    }
                    scheduleMode = normalizeScheduleMode((_a = payload.scheduleMode) !== null && _a !== void 0 ? _a : currentRow.schedule_mode);
                    repeatIntervalValue = normalizeRepeatIntervalValue((_d = (_c = (_b = payload.repeatIntervalValue) !== null && _b !== void 0 ? _b : currentRow.repeat_interval_value) !== null && _c !== void 0 ? _c : currentRow.repeat_interval_minutes) !== null && _d !== void 0 ? _d : 60);
                    repeatIntervalUnit = normalizeRepeatIntervalUnit((_e = payload.repeatIntervalUnit) !== null && _e !== void 0 ? _e : currentRow.repeat_interval_unit);
                    executionMode = normalizeScheduleExecutionMode((_f = payload.executionMode) !== null && _f !== void 0 ? _f : currentRow.execution_mode);
                    return [4 /*yield*/, (0, automation_type_config_service_js_1.resolveAutomationType)((_h = (_g = payload.automationType) !== null && _g !== void 0 ? _g : currentRow.automation_type_id) !== null && _h !== void 0 ? _h : currentRow.automation_type)];
                case 3:
                    automationType = _25.sent();
                    repeatWindows = normalizeScheduleTimeWindows((_j = payload.repeatWindows) !== null && _j !== void 0 ? _j : resolveScheduleTimeWindows(currentRow));
                    firstRepeatWindow = (_k = repeatWindows[0]) !== null && _k !== void 0 ? _k : null;
                    shouldRecreateManagedService = executionMode === 'managed-service' &&
                        (normalizeBoolean(payload.recreateManagedServiceOnNextSave, false)
                            || executionMode !== normalizeScheduleExecutionMode(currentRow.execution_mode)
                            || (payload.workId !== undefined && normalizeScheduledWorkId(payload.workId) !== String((_l = currentRow.work_id) !== null && _l !== void 0 ? _l : '')));
                    return [4 /*yield*/, (0, client_js_1.db)(exports.PLAN_SCHEDULED_TASK_TABLE)
                            .where({ id: id })
                            .update({
                            work_id: payload.workId === undefined ? currentRow.work_id : normalizeScheduledWorkId(payload.workId),
                            note: (_m = payload.note) !== null && _m !== void 0 ? _m : currentRow.note,
                            automation_type: automationType.behaviorType,
                            automation_type_id: automationType.id,
                            automation_context_ids_json: (0, automation_context_service_js_1.stringifyAutomationContextIds)((_o = payload.automationContextIds) !== null && _o !== void 0 ? _o : (0, automation_context_service_js_1.parseAutomationContextIds)(currentRow.automation_context_ids_json)),
                            release_target: (_q = (_p = payload.releaseTarget) !== null && _p !== void 0 ? _p : currentRow.release_target) !== null && _q !== void 0 ? _q : 'release',
                            jangsing_processing_required: (_s = (_r = payload.jangsingProcessingRequired) !== null && _r !== void 0 ? _r : currentRow.jangsing_processing_required) !== null && _s !== void 0 ? _s : true,
                            auto_deploy_to_main: (_u = (_t = payload.autoDeployToMain) !== null && _t !== void 0 ? _t : currentRow.auto_deploy_to_main) !== null && _u !== void 0 ? _u : true,
                            suppress_web_push: (_w = (_v = payload.suppressWebPush) !== null && _v !== void 0 ? _v : currentRow.suppress_web_push) !== null && _w !== void 0 ? _w : false,
                            enabled: (_y = (_x = payload.enabled) !== null && _x !== void 0 ? _x : currentRow.enabled) !== null && _y !== void 0 ? _y : true,
                            immediate_run_enabled: (_0 = (_z = payload.immediateRunEnabled) !== null && _z !== void 0 ? _z : currentRow.immediate_run_enabled) !== null && _0 !== void 0 ? _0 : true,
                            context_snapshot_refresh_requested: (_2 = (_1 = payload.refreshContextSnapshotOnNextRun) !== null && _1 !== void 0 ? _1 : currentRow.context_snapshot_refresh_requested) !== null && _2 !== void 0 ? _2 : false,
                            execution_mode: executionMode,
                            managed_service_recreate_requested: shouldRecreateManagedService,
                            managed_service_generation_plan_item_id: shouldRecreateManagedService || executionMode !== normalizeScheduleExecutionMode(currentRow.execution_mode)
                                ? null
                                : (_3 = currentRow.managed_service_generation_plan_item_id) !== null && _3 !== void 0 ? _3 : null,
                            managed_service_generation_board_post_id: shouldRecreateManagedService || executionMode !== normalizeScheduleExecutionMode(currentRow.execution_mode)
                                ? null
                                : (_4 = currentRow.managed_service_generation_board_post_id) !== null && _4 !== void 0 ? _4 : null,
                            schedule_mode: scheduleMode,
                            repeat_interval_value: repeatIntervalValue,
                            repeat_interval_unit: repeatIntervalUnit,
                            repeat_interval_seconds: toRepeatIntervalSeconds(repeatIntervalValue, repeatIntervalUnit),
                            repeat_interval_minutes: toRepeatIntervalMinutes(repeatIntervalValue, repeatIntervalUnit),
                            daily_run_time: normalizeDailyRunTime((_5 = payload.dailyRunTime) !== null && _5 !== void 0 ? _5 : currentRow.daily_run_time),
                            schedule_weekdays_json: stringifyScheduleWeekdays((_6 = payload.scheduleWeekdays) !== null && _6 !== void 0 ? _6 : parseScheduleWeekdays(currentRow.schedule_weekdays_json)),
                            schedule_date_ranges_json: stringifyScheduleDateRanges((_7 = payload.scheduleDateRanges) !== null && _7 !== void 0 ? _7 : parseScheduleDateRanges(currentRow.schedule_date_ranges_json)),
                            repeat_windows_json: stringifyScheduleTimeWindows(repeatWindows),
                            repeat_window_start_time: (_8 = firstRepeatWindow === null || firstRepeatWindow === void 0 ? void 0 : firstRepeatWindow.startTime) !== null && _8 !== void 0 ? _8 : null,
                            repeat_window_end_time: (_9 = firstRepeatWindow === null || firstRepeatWindow === void 0 ? void 0 : firstRepeatWindow.endTime) !== null && _9 !== void 0 ? _9 : null,
                            context_snapshot_generated_at: payload.enabled !== undefined && Boolean(payload.enabled) !== Boolean((_10 = currentRow.enabled) !== null && _10 !== void 0 ? _10 : true)
                                ? null
                                : (_11 = currentRow.context_snapshot_generated_at) !== null && _11 !== void 0 ? _11 : null,
                            updated_at: client_js_1.db.fn.now(),
                        })
                            .returning('*')];
                case 4:
                    rows = _25.sent();
                    row = (_12 = rows[0]) !== null && _12 !== void 0 ? _12 : null;
                    if (!row) {
                        return [2 /*return*/, null];
                    }
                    if (!(executionMode !== 'managed-service')) return [3 /*break*/, 7];
                    return [4 /*yield*/, removeManagedServicePackage(Number(row.id))];
                case 5:
                    _25.sent();
                    return [4 /*yield*/, (0, client_js_1.db)(exports.PLAN_SCHEDULED_TASK_TABLE)
                            .where({ id: row.id })
                            .update({
                            managed_service_key: null,
                            managed_service_package_name: null,
                            managed_service_directory: null,
                            managed_service_manifest_path: null,
                            managed_service_generated_at: null,
                            managed_service_generation_plan_item_id: null,
                            managed_service_generation_board_post_id: null,
                            managed_service_recreate_requested: false,
                            updated_at: client_js_1.db.fn.now(),
                        })
                            .returning('*')];
                case 6:
                    updatedRows = _25.sent();
                    return [2 /*return*/, (_13 = updatedRows[0]) !== null && _13 !== void 0 ? _13 : row];
                case 7:
                    if (!(shouldRecreateManagedService
                        || !String((_14 = row.managed_service_directory) !== null && _14 !== void 0 ? _14 : '').trim()
                        || !String((_15 = row.managed_service_key) !== null && _15 !== void 0 ? _15 : '').trim())) return [3 /*break*/, 11];
                    return [4 /*yield*/, removeManagedServicePackage(Number(row.id))];
                case 8:
                    _25.sent();
                    return [4 /*yield*/, ensureManagedServicePackage({
                            scheduleId: Number(row.id),
                            workId: String((_17 = (_16 = row.work_id) !== null && _16 !== void 0 ? _16 : currentRow.work_id) !== null && _17 !== void 0 ? _17 : '반복작업'),
                            note: String((_19 = (_18 = row.note) !== null && _18 !== void 0 ? _18 : currentRow.note) !== null && _19 !== void 0 ? _19 : ''),
                            releaseTarget: String((_21 = (_20 = row.release_target) !== null && _20 !== void 0 ? _20 : currentRow.release_target) !== null && _21 !== void 0 ? _21 : 'release'),
                            automationType: String((_23 = (_22 = row.automation_type_id) !== null && _22 !== void 0 ? _22 : row.automation_type) !== null && _23 !== void 0 ? _23 : automationType.id),
                        })];
                case 9:
                    managedService = _25.sent();
                    return [4 /*yield*/, (0, client_js_1.db)(exports.PLAN_SCHEDULED_TASK_TABLE)
                            .where({ id: row.id })
                            .update({
                            managed_service_key: managedService.serviceKey,
                            managed_service_package_name: managedService.packageName,
                            managed_service_directory: managedService.relativeDirectory,
                            managed_service_manifest_path: managedService.manifestPath,
                            managed_service_generated_at: null,
                            managed_service_generation_plan_item_id: null,
                            managed_service_generation_board_post_id: null,
                            managed_service_recreate_requested: shouldRecreateManagedService,
                            updated_at: client_js_1.db.fn.now(),
                        })
                            .returning('*')];
                case 10:
                    updatedRows = _25.sent();
                    row = (_24 = updatedRows[0]) !== null && _24 !== void 0 ? _24 : row;
                    _25.label = 11;
                case 11: return [2 /*return*/, row];
            }
        });
    });
}
function deletePlanScheduledTask(id) {
    return __awaiter(this, void 0, void 0, function () {
        var currentRow;
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0: return [4 /*yield*/, ensurePlanScheduledTaskTable()];
                case 1:
                    _a.sent();
                    return [4 /*yield*/, (0, client_js_1.db)(exports.PLAN_SCHEDULED_TASK_TABLE).where({ id: id }).first()];
                case 2:
                    currentRow = _a.sent();
                    if (!currentRow) {
                        return [2 /*return*/, null];
                    }
                    return [4 /*yield*/, removeManagedServicePackage(id)];
                case 3:
                    _a.sent();
                    return [4 /*yield*/, (0, client_js_1.db)(exports.PLAN_SCHEDULED_TASK_TABLE).where({ id: id }).delete()];
                case 4:
                    _a.sent();
                    return [2 /*return*/, currentRow];
            }
        });
    });
}
function registerDuePlanScheduledTasks() {
    return __awaiter(this, arguments, void 0, function (now) {
        var rows, registered, _i, _a, row, registration;
        if (now === void 0) { now = new Date(); }
        return __generator(this, function (_b) {
            switch (_b.label) {
                case 0: return [4 /*yield*/, (0, plan_service_js_1.ensurePlanTable)()];
                case 1:
                    _b.sent();
                    return [4 /*yield*/, ensurePlanScheduledTaskTable()];
                case 2:
                    _b.sent();
                    return [4 /*yield*/, (0, client_js_1.db)(exports.PLAN_SCHEDULED_TASK_TABLE).where({ enabled: true }).orderBy('id', 'asc')];
                case 3:
                    rows = _b.sent();
                    registered = [];
                    _i = 0, _a = rows.filter(function (item) { return isScheduleDue(item, now); });
                    _b.label = 4;
                case 4:
                    if (!(_i < _a.length)) return [3 /*break*/, 7];
                    row = _a[_i];
                    return [4 /*yield*/, registerPlanScheduledTaskRow(row, now)];
                case 5:
                    registration = _b.sent();
                    if (registration.createdPlan || registration.createdBoardPosts.length > 0) {
                        registered.push(registration);
                    }
                    _b.label = 6;
                case 6:
                    _i++;
                    return [3 /*break*/, 4];
                case 7: return [2 /*return*/, registered];
            }
        });
    });
}
function registerPlanScheduledTaskRow(row, now) {
    return __awaiter(this, void 0, void 0, function () {
        var executionMode, automationContextIds, shouldRefreshSnapshot, scheduleSnapshot, _a, managedServiceReady, effectiveRow, scheduleNote, managedServiceDirectory, managedServiceResult, createdPlan, managedServiceChangedFiles, boardPost;
        var _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w;
        return __generator(this, function (_x) {
            switch (_x.label) {
                case 0:
                    executionMode = normalizeScheduleExecutionMode(row.execution_mode);
                    automationContextIds = (0, automation_context_service_js_1.parseAutomationContextIds)(row.automation_context_ids_json);
                    shouldRefreshSnapshot = !row.context_snapshot_generated_at || normalizeBoolean(row.context_snapshot_refresh_requested, false);
                    if (!shouldRefreshSnapshot) return [3 /*break*/, 2];
                    return [4 /*yield*/, (0, automation_context_service_js_1.ensureSchedulePromptSnapshot)({
                            scheduleId: Number(row.id),
                            workId: buildScheduledPlanWorkIdBase(row),
                            note: String((_b = row.note) !== null && _b !== void 0 ? _b : ''),
                            forceRefresh: true,
                        })];
                case 1:
                    _a = _x.sent();
                    return [3 /*break*/, 3];
                case 2:
                    _a = {
                        directory: ".auto_codex/schedule/".concat(row.id),
                        requestPath: ".auto_codex/schedule/".concat(row.id, "/request.md"),
                        contextPath: ".auto_codex/schedule/".concat(row.id, "/context.md"),
                        manifestPath: ".auto_codex/schedule/".concat(row.id, "/manifest.json"),
                    };
                    _x.label = 3;
                case 3:
                    scheduleSnapshot = _a;
                    return [4 /*yield*/, ensureManagedServiceExecutionReady({
                            row: row,
                            scheduleSnapshot: scheduleSnapshot,
                            automationContextIds: automationContextIds,
                        })];
                case 4:
                    managedServiceReady = _x.sent();
                    effectiveRow = managedServiceReady.row;
                    scheduleNote = [
                        String((_c = effectiveRow.note) !== null && _c !== void 0 ? _c : '').trim(),
                        '',
                        '## 스케줄 전용 참조 문서',
                        "- ".concat(scheduleSnapshot.requestPath),
                        "- ".concat(scheduleSnapshot.contextPath),
                        '',
                        '위 경로의 Markdown 문서를 먼저 읽고 처리하세요. 원본 소스/문서 재탐색은 꼭 필요한 경우에만 제한적으로 수행하세요.',
                        executionMode === 'managed-service'
                            ? [
                                '',
                                '## 스케줄 관리 서비스',
                                "- \uC11C\uBE44\uC2A4 \uD0A4: ".concat(String((_d = effectiveRow.managed_service_key) !== null && _d !== void 0 ? _d : "schedule-".concat(effectiveRow.id, "-service"))),
                                "- \uC11C\uBE44\uC2A4 \uACBD\uB85C: ".concat(String((_e = effectiveRow.managed_service_directory) !== null && _e !== void 0 ? _e : ".auto_codex/schedule/".concat(effectiveRow.id))),
                                managedServiceReady.ready
                                    ? '- 현재 생성된 스케줄 전용 서비스 파일을 직접 실행합니다.'
                                    : "- \uD604\uC7AC \uC11C\uBE44\uC2A4 \uD328\uD0A4\uC9C0 \uC0DD\uC131 Plan\uC744 ".concat(managedServiceReady.generationTriggered ? '자동 접수했으며' : '이미 접수해 두었으며', " \uC0DD\uC131 \uC644\uB8CC \uC804\uAE4C\uC9C0 \uC2E4\uC81C \uC11C\uBE44\uC2A4 \uC2E4\uD589\uC740 \uBCF4\uB958\uD569\uB2C8\uB2E4."),
                                managedServiceReady.reason
                                    ? "- \uC0DD\uC131 \uC0AC\uC720: ".concat(managedServiceReady.reason === 'missing' ? '패키지 누락 감지' : '패키지 재생성 요청')
                                    : null,
                                '- 서비스 구현은 Codex CLI가 `.auto_codex/schedule/{id}` 아래 파일을 생성한 결과물을 사용합니다.',
                            ].join('\n')
                            : null,
                    ]
                        .filter(function (value) { return Boolean(value); })
                        .join('\n')
                        .trim();
                    if (!(executionMode === 'managed-service')) return [3 /*break*/, 10];
                    if (!managedServiceReady.ready) {
                        return [2 /*return*/, {
                                createdPlan: managedServiceReady.createdPlan,
                                createdBoardPosts: managedServiceReady.createdBoardPosts,
                            }];
                    }
                    managedServiceDirectory = String((_f = effectiveRow.managed_service_directory) !== null && _f !== void 0 ? _f : ".auto_codex/schedule/".concat(effectiveRow.id));
                    return [4 /*yield*/, (0, managed_schedule_service_js_1.runManagedScheduleService)(managedServiceDirectory)];
                case 5:
                    managedServiceResult = _x.sent();
                    if (!managedServiceResult.ok) {
                        throw new Error("\uC2A4\uCF00\uC904 \uC11C\uBE44\uC2A4 \uC2E4\uD589 \uC2E4\uD328: ".concat(buildManagedServiceFailureSummary(managedServiceResult)));
                    }
                    return [4 /*yield*/, (0, plan_service_js_1.createCompletedPlanExecutionLogItem)({
                            workId: buildScheduledPlanWorkIdBase(effectiveRow),
                            note: scheduleNote,
                            automationType: String((_h = (_g = effectiveRow.automation_type_id) !== null && _g !== void 0 ? _g : effectiveRow.automation_type) !== null && _h !== void 0 ? _h : 'none'),
                            automationContextIds: automationContextIds,
                            releaseTarget: String((_j = effectiveRow.release_target) !== null && _j !== void 0 ? _j : 'release'),
                            jangsingProcessingRequired: Boolean((_k = effectiveRow.jangsing_processing_required) !== null && _k !== void 0 ? _k : true),
                            autoDeployToMain: Boolean((_l = effectiveRow.auto_deploy_to_main) !== null && _l !== void 0 ? _l : true),
                            suppressWebPush: Boolean((_m = effectiveRow.suppress_web_push) !== null && _m !== void 0 ? _m : false),
                            repeatRequestEnabled: false,
                            repeatIntervalMinutes: 60,
                        })];
                case 6:
                    createdPlan = _x.sent();
                    managedServiceChangedFiles = [
                        "".concat(managedServiceDirectory, "/README.md"),
                        "".concat(managedServiceDirectory, "/service.ts"),
                        "".concat(managedServiceDirectory, "/service.mjs"),
                        "".concat(managedServiceDirectory, "/service-manifest.json"),
                    ];
                    return [4 /*yield*/, (0, plan_service_js_1.createPlanSourceWorkHistory)(Number(createdPlan.id), {
                            summary: [
                                "\uC2A4\uCF00\uC904 \uC11C\uBE44\uC2A4 \uC2E4\uD589: schedule #".concat(effectiveRow.id),
                                "\uC11C\uBE44\uC2A4 \uD0A4: ".concat(String((_o = effectiveRow.managed_service_key) !== null && _o !== void 0 ? _o : "schedule-".concat(effectiveRow.id, "-service"))),
                                "\uACB0\uACFC: ".concat(managedServiceResult.skipped
                                    ? "\uC2A4\uD0B5 (".concat((_q = (_p = managedServiceResult.web.reason) !== null && _p !== void 0 ? _p : managedServiceResult.ios.reason) !== null && _q !== void 0 ? _q : '사유 없음', ")")
                                    : "".concat(managedServiceResult.itemCount, "\uAC74 \uC804\uC1A1 \uC2DC\uB3C4")),
                            ].join('\n'),
                            branchName: String((_s = (_r = createdPlan.releaseTarget) !== null && _r !== void 0 ? _r : createdPlan.assignedBranch) !== null && _s !== void 0 ? _s : 'main'),
                            commitHash: null,
                            changedFiles: managedServiceChangedFiles,
                            commandLog: [
                                "schedule-managed-service run scheduleId=".concat(String(effectiveRow.id)),
                                "servicePath=".concat(managedServiceDirectory, "/service.mjs"),
                                "itemCount=".concat(managedServiceResult.itemCount),
                                "webSent=".concat(managedServiceResult.web.sentCount),
                                "webFailed=".concat(managedServiceResult.web.failedCount),
                                "skipped=".concat(managedServiceResult.skipped ? 'true' : 'false'),
                                "reason=".concat((_u = (_t = managedServiceResult.web.reason) !== null && _t !== void 0 ? _t : managedServiceResult.ios.reason) !== null && _u !== void 0 ? _u : ''),
                            ].join('\n'),
                            diffText: null,
                            sourceFiles: [],
                        })];
                case 7:
                    _x.sent();
                    return [4 /*yield*/, (0, plan_service_js_1.createPlanActionHistory)(Number(createdPlan.id), '스케줄서비스실행', "Plan \uC2A4\uCF00\uC904 #".concat(effectiveRow.id, " \uC804\uC6A9 \uC11C\uBE44\uC2A4 \uD30C\uC77C\uC744 \uC9C1\uC811 \uC2E4\uD589\uD588\uC2B5\uB2C8\uB2E4."))];
                case 8:
                    _x.sent();
                    return [4 /*yield*/, (0, client_js_1.db)(exports.PLAN_SCHEDULED_TASK_TABLE)
                            .where({ id: effectiveRow.id })
                            .update({
                            last_registered_at: now,
                            context_snapshot_generated_at: now,
                            context_snapshot_refresh_requested: false,
                            managed_service_generated_at: client_js_1.db.fn.now(),
                            updated_at: client_js_1.db.fn.now(),
                        })];
                case 9:
                    _x.sent();
                    return [2 /*return*/, {
                            createdPlan: createdPlan,
                            createdBoardPosts: [],
                        }];
                case 10: return [4 /*yield*/, (0, board_service_js_1.createBoardPost)({
                        title: buildScheduledBoardPostTitle(effectiveRow),
                        content: scheduleNote,
                        attachments: [],
                        automationType: String((_w = (_v = effectiveRow.automation_type_id) !== null && _v !== void 0 ? _v : effectiveRow.automation_type) !== null && _w !== void 0 ? _w : 'none'),
                        automationContextIds: automationContextIds,
                        requestExecutionMode: 'all_at_once',
                        requestItems: [],
                    })];
                case 11:
                    boardPost = _x.sent();
                    return [4 /*yield*/, (0, client_js_1.db)(exports.PLAN_SCHEDULED_TASK_TABLE)
                            .where({ id: effectiveRow.id })
                            .update({
                            last_registered_at: now,
                            context_snapshot_generated_at: now,
                            context_snapshot_refresh_requested: false,
                            updated_at: client_js_1.db.fn.now(),
                        })];
                case 12:
                    _x.sent();
                    return [2 /*return*/, {
                            createdPlan: null,
                            createdBoardPosts: [boardPost],
                        }];
            }
        });
    });
}
function registerPlanScheduledTaskNow(id_1) {
    return __awaiter(this, arguments, void 0, function (id, now, options) {
        var row, _a;
        if (now === void 0) { now = new Date(); }
        return __generator(this, function (_b) {
            switch (_b.label) {
                case 0: return [4 /*yield*/, (0, plan_service_js_1.ensurePlanTable)()];
                case 1:
                    _b.sent();
                    return [4 /*yield*/, ensurePlanScheduledTaskTable()];
                case 2:
                    _b.sent();
                    if (!(options === null || options === void 0 ? void 0 : options.forceManagedServiceGeneration)) return [3 /*break*/, 4];
                    return [4 /*yield*/, (0, client_js_1.db)(exports.PLAN_SCHEDULED_TASK_TABLE).where({ id: id }).first()];
                case 3:
                    _a = _b.sent();
                    return [3 /*break*/, 6];
                case 4: return [4 /*yield*/, (0, client_js_1.db)(exports.PLAN_SCHEDULED_TASK_TABLE).where({ id: id, enabled: true }).first()];
                case 5:
                    _a = _b.sent();
                    _b.label = 6;
                case 6:
                    row = _a;
                    if (!row
                        || (!(options === null || options === void 0 ? void 0 : options.forceManagedServiceGeneration) && !(options === null || options === void 0 ? void 0 : options.ignoreScheduleDue) && !isScheduleDue(row, now))) {
                        return [2 /*return*/, null];
                    }
                    return [2 /*return*/, registerPlanScheduledTaskRow(row, now)];
            }
        });
    });
}
