"use strict";
var __assign = (this && this.__assign) || function () {
    __assign = Object.assign || function(t) {
        for (var s, i = 1, n = arguments.length; i < n; i++) {
            s = arguments[i];
            for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
                t[p] = s[p];
        }
        return t;
    };
    return __assign.apply(this, arguments);
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __generator = (this && this.__generator) || function (thisArg, body) {
    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
    return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
    function verb(n) { return function (v) { return step([n, v]); }; }
    function step(op) {
        if (f) throw new TypeError("Generator is already executing.");
        while (g && (g = 0, op[0] && (_ = 0)), _) try {
            if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
            if (y = 0, t) op = [op[0] & 2, t.value];
            switch (op[0]) {
                case 0: case 1: t = op; break;
                case 4: _.label++; return { value: op[1], done: false };
                case 5: _.label++; y = op[1]; op = [0]; continue;
                case 7: op = _.ops.pop(); _.trys.pop(); continue;
                default:
                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
                    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
                    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
                    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
                    if (t[2]) _.ops.pop();
                    _.trys.pop(); continue;
            }
            op = body.call(thisArg, _);
        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
        if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
    }
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.createErrorLogSchema = exports.ERROR_LOG_VIEW_TOKEN = exports.ERROR_LOG_TABLE = void 0;
exports.setupErrorLogTable = setupErrorLogTable;
exports.createErrorLog = createErrorLog;
exports.listErrorLogs = listErrorLogs;
exports.hasErrorLogViewAccessToken = hasErrorLogViewAccessToken;
var zod_1 = require("zod");
var client_js_1 = require("../db/client.js");
exports.ERROR_LOG_TABLE = 'error_logs';
exports.ERROR_LOG_VIEW_TOKEN = 'usr_7f3a9c2d8e1b4a6f';
exports.createErrorLogSchema = zod_1.z.object({
    source: zod_1.z.enum(['server', 'client', 'automation']).default('server'),
    sourceLabel: zod_1.z.string().trim().max(80).optional().nullable(),
    errorType: zod_1.z.string().trim().min(1).max(120),
    errorName: zod_1.z.string().trim().max(255).optional().nullable(),
    errorMessage: zod_1.z.string().trim().min(1).max(10000),
    detail: zod_1.z.string().trim().max(50000).optional().nullable(),
    stackTrace: zod_1.z.string().trim().max(50000).optional().nullable(),
    statusCode: zod_1.z.number().int().min(100).max(599).optional().nullable(),
    requestMethod: zod_1.z.string().trim().max(10).optional().nullable(),
    requestPath: zod_1.z.string().trim().max(1000).optional().nullable(),
    relatedPlanId: zod_1.z.number().int().positive().optional().nullable(),
    relatedWorkId: zod_1.z.string().trim().max(120).optional().nullable(),
    context: zod_1.z.record(zod_1.z.string(), zod_1.z.unknown()).optional().nullable(),
});
function ensureErrorLogTable() {
    return __awaiter(this, void 0, void 0, function () {
        var hasTable, requiredColumns, _loop_1, _i, requiredColumns_1, _a, columnName, createColumn;
        return __generator(this, function (_b) {
            switch (_b.label) {
                case 0: return [4 /*yield*/, client_js_1.db.schema.hasTable(exports.ERROR_LOG_TABLE)];
                case 1:
                    hasTable = _b.sent();
                    if (!!hasTable) return [3 /*break*/, 3];
                    return [4 /*yield*/, client_js_1.db.schema.createTable(exports.ERROR_LOG_TABLE, function (table) {
                            table.increments('id').primary();
                            table.string('source', 20).notNullable().defaultTo('server');
                            table.string('source_label', 80).nullable();
                            table.string('error_type', 120).notNullable();
                            table.string('error_name', 255).nullable();
                            table.text('error_message').notNullable();
                            table.text('detail').nullable();
                            table.text('stack_trace').nullable();
                            table.integer('status_code').nullable();
                            table.string('request_method', 10).nullable();
                            table.string('request_path', 1000).nullable();
                            table.integer('related_plan_id').nullable();
                            table.string('related_work_id', 120).nullable();
                            table.jsonb('context_json').nullable();
                            table.timestamp('created_at', { useTz: true }).notNullable().defaultTo(client_js_1.db.fn.now());
                        })];
                case 2:
                    _b.sent();
                    return [2 /*return*/];
                case 3:
                    requiredColumns = [
                        ['source', function (table) { return table.string('source', 20).notNullable().defaultTo('server'); }],
                        ['source_label', function (table) { return table.string('source_label', 80).nullable(); }],
                        ['error_type', function (table) { return table.string('error_type', 120).notNullable().defaultTo('unknown'); }],
                        ['error_name', function (table) { return table.string('error_name', 255).nullable(); }],
                        ['error_message', function (table) { return table.text('error_message').notNullable().defaultTo(''); }],
                        ['detail', function (table) { return table.text('detail').nullable(); }],
                        ['stack_trace', function (table) { return table.text('stack_trace').nullable(); }],
                        ['status_code', function (table) { return table.integer('status_code').nullable(); }],
                        ['request_method', function (table) { return table.string('request_method', 10).nullable(); }],
                        ['request_path', function (table) { return table.string('request_path', 1000).nullable(); }],
                        ['related_plan_id', function (table) { return table.integer('related_plan_id').nullable(); }],
                        ['related_work_id', function (table) { return table.string('related_work_id', 120).nullable(); }],
                        ['context_json', function (table) { return table.jsonb('context_json').nullable(); }],
                        ['created_at', function (table) { return table.timestamp('created_at', { useTz: true }).notNullable().defaultTo(client_js_1.db.fn.now()); }],
                    ];
                    _loop_1 = function (columnName, createColumn) {
                        var hasColumn;
                        return __generator(this, function (_c) {
                            switch (_c.label) {
                                case 0: return [4 /*yield*/, client_js_1.db.schema.hasColumn(exports.ERROR_LOG_TABLE, columnName)];
                                case 1:
                                    hasColumn = _c.sent();
                                    if (!!hasColumn) return [3 /*break*/, 3];
                                    return [4 /*yield*/, client_js_1.db.schema.alterTable(exports.ERROR_LOG_TABLE, function (table) {
                                            createColumn(table);
                                        })];
                                case 2:
                                    _c.sent();
                                    _c.label = 3;
                                case 3: return [2 /*return*/];
                            }
                        });
                    };
                    _i = 0, requiredColumns_1 = requiredColumns;
                    _b.label = 4;
                case 4:
                    if (!(_i < requiredColumns_1.length)) return [3 /*break*/, 7];
                    _a = requiredColumns_1[_i], columnName = _a[0], createColumn = _a[1];
                    return [5 /*yield**/, _loop_1(columnName, createColumn)];
                case 5:
                    _b.sent();
                    _b.label = 6;
                case 6:
                    _i++;
                    return [3 /*break*/, 4];
                case 7: return [2 /*return*/];
            }
        });
    });
}
function normalizePayload(payload) {
    var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
    var parsedPayload = exports.createErrorLogSchema.parse(payload);
    var sourceLabel = (_a = parsedPayload.sourceLabel) !== null && _a !== void 0 ? _a : (parsedPayload.source === 'client'
        ? '프론트엔드'
        : parsedPayload.source === 'automation'
            ? 'Plan 자동화'
            : '워크서버 API');
    return {
        source: parsedPayload.source,
        source_label: sourceLabel,
        error_type: parsedPayload.errorType,
        error_name: (_b = parsedPayload.errorName) !== null && _b !== void 0 ? _b : null,
        error_message: parsedPayload.errorMessage,
        detail: (_c = parsedPayload.detail) !== null && _c !== void 0 ? _c : null,
        stack_trace: (_d = parsedPayload.stackTrace) !== null && _d !== void 0 ? _d : null,
        status_code: (_e = parsedPayload.statusCode) !== null && _e !== void 0 ? _e : null,
        request_method: (_f = parsedPayload.requestMethod) !== null && _f !== void 0 ? _f : null,
        request_path: (_g = parsedPayload.requestPath) !== null && _g !== void 0 ? _g : null,
        related_plan_id: (_h = parsedPayload.relatedPlanId) !== null && _h !== void 0 ? _h : null,
        related_work_id: (_j = parsedPayload.relatedWorkId) !== null && _j !== void 0 ? _j : null,
        context_json: (_k = parsedPayload.context) !== null && _k !== void 0 ? _k : null,
    };
}
function mapErrorLogRow(row) {
    var _a, _b, _c;
    return {
        id: Number(row.id),
        source: String((_a = row.source) !== null && _a !== void 0 ? _a : 'server'),
        sourceLabel: row.source_label ? String(row.source_label) : null,
        errorType: String((_b = row.error_type) !== null && _b !== void 0 ? _b : ''),
        errorName: row.error_name ? String(row.error_name) : null,
        errorMessage: String((_c = row.error_message) !== null && _c !== void 0 ? _c : ''),
        detail: row.detail ? String(row.detail) : null,
        stackTrace: row.stack_trace ? String(row.stack_trace) : null,
        statusCode: typeof row.status_code === 'number' ? row.status_code : row.status_code ? Number(row.status_code) : null,
        requestMethod: row.request_method ? String(row.request_method) : null,
        requestPath: row.request_path ? String(row.request_path) : null,
        relatedPlanId: typeof row.related_plan_id === 'number'
            ? row.related_plan_id
            : row.related_plan_id
                ? Number(row.related_plan_id)
                : null,
        relatedWorkId: row.related_work_id ? String(row.related_work_id) : null,
        context: row.context_json && typeof row.context_json === 'object' ? row.context_json : null,
        createdAt: row.created_at,
    };
}
function setupErrorLogTable() {
    return __awaiter(this, void 0, void 0, function () {
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0: return [4 /*yield*/, ensureErrorLogTable()];
                case 1:
                    _a.sent();
                    return [2 /*return*/, {
                            ok: true,
                            table: exports.ERROR_LOG_TABLE,
                        }];
            }
        });
    });
}
function createErrorLog(payload) {
    return __awaiter(this, void 0, void 0, function () {
        var row;
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0: return [4 /*yield*/, ensureErrorLogTable()];
                case 1:
                    _a.sent();
                    return [4 /*yield*/, (0, client_js_1.db)(exports.ERROR_LOG_TABLE)
                            .insert(__assign(__assign({}, normalizePayload(payload)), { created_at: client_js_1.db.fn.now() }))
                            .returning('*')];
                case 2:
                    row = (_a.sent())[0];
                    return [2 /*return*/, mapErrorLogRow(row)];
            }
        });
    });
}
function listErrorLogs() {
    return __awaiter(this, arguments, void 0, function (limit) {
        var safeLimit, rows;
        if (limit === void 0) { limit = 50; }
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0: return [4 /*yield*/, ensureErrorLogTable()];
                case 1:
                    _a.sent();
                    safeLimit = Number.isFinite(limit) ? Math.min(Math.max(Math.trunc(limit), 1), 200) : 50;
                    return [4 /*yield*/, (0, client_js_1.db)(exports.ERROR_LOG_TABLE).select('*').orderBy('created_at', 'desc').limit(safeLimit)];
                case 2:
                    rows = _a.sent();
                    return [2 /*return*/, rows.map(function (row) { return mapErrorLogRow(row); })];
            }
        });
    });
}
function hasErrorLogViewAccessToken(token) {
    var normalizedToken = Array.isArray(token) ? token[0] : token;
    return String(normalizedToken !== null && normalizedToken !== void 0 ? normalizedToken : '').trim() === exports.ERROR_LOG_VIEW_TOKEN;
}
