"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());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.RunDao = void 0;
const Run_1 = require("../models/Run");
const utils_1 = require("../utils");
const RunView_1 = require("../models/RunView");
const typeorm_1 = require("typeorm");
const src_1 = require("../../../shared/src");
class RunDao {
    static doesProjectExist(project) {
        return __awaiter(this, void 0, void 0, function* () {
            try {
                const run = yield Run_1.RunTable.findOne({ where: { project } });
                return run !== null;
            }
            catch (error) {
                console.error(error);
                throw error;
            }
        });
    }
    static doesRunExist(runId) {
        return __awaiter(this, void 0, void 0, function* () {
            try {
                const run = yield Run_1.RunTable.findOne({ where: { id: runId } });
                return run !== null;
            }
            catch (error) {
                console.error(error);
                throw error;
            }
        });
    }
    static addRun(runData) {
        return __awaiter(this, void 0, void 0, function* () {
            try {
                const run = Run_1.RunTable.create(Object.assign({}, runData));
                yield run.save();
            }
            catch (error) {
                console.error(error);
                throw error;
            }
        });
    }
    static getAllProjects() {
        return __awaiter(this, void 0, void 0, function* () {
            try {
                const result = yield Run_1.RunTable.createQueryBuilder('run')
                    .select('DISTINCT run.project', 'project')
                    .addSelect((qb) => qb
                    .select('COUNT(*)')
                    .from(Run_1.RunTable, 'r')
                    .where('r.project = run.project')
                    .andWhere('r.status = :running', {
                    running: src_1.Status.RUNNING,
                }), 'running')
                    .addSelect((qb) => qb
                    .select('COUNT(*)')
                    .from(Run_1.RunTable, 'r')
                    .where('r.project = run.project')
                    .andWhere('r.status = :pending', {
                    pending: src_1.Status.PENDING,
                }), 'pending')
                    .addSelect((qb) => qb
                    .select('COUNT(*)')
                    .from(Run_1.RunTable, 'r')
                    .where('r.project = run.project')
                    .andWhere('r.status = :finished', {
                    finished: src_1.Status.DONE,
                }), 'finished')
                    .addSelect((qb) => qb
                    .select('MIN(r.timestamp)')
                    .from(Run_1.RunTable, 'r')
                    .where('r.project = run.project'), 'createdAt')
                    .groupBy('run.project')
                    .getRawMany();
                return result.map((row) => ({
                    project: row.project,
                    running: parseInt(row.running),
                    pending: parseInt(row.pending),
                    finished: parseInt(row.finished),
                    total: parseInt(row.running) +
                        parseInt(row.pending) +
                        parseInt(row.finished),
                    createdAt: row.createdAt,
                }));
            }
            catch (error) {
                console.error(error);
                throw error;
            }
        });
    }
    /*
     * Get all runs for a project
     */
    static getAllProjectRuns(project) {
        return __awaiter(this, void 0, void 0, function* () {
            try {
                const result = yield Run_1.RunTable.find({
                    where: { project },
                    order: { timestamp: 'DESC' },
                });
                return result.map((row) => ({
                    id: row.id,
                    project: row.project,
                    name: row.name,
                    timestamp: row.timestamp,
                    run_dir: row.run_dir,
                    pid: row.pid,
                    status: row.status,
                }));
            }
            catch (error) {
                console.error(error);
                throw error;
            }
        });
    }
    static getRunData(runId) {
        return __awaiter(this, void 0, void 0, function* () {
            try {
                const result = yield Run_1.RunTable.findOne({
                    where: { id: runId },
                    relations: ['messages', 'inputRequests', 'spans'],
                });
                if (result) {
                    return {
                        runData: {
                            id: result.id,
                            project: result.project,
                            name: result.name,
                            timestamp: result.timestamp,
                            run_dir: result.run_dir,
                            pid: result.pid,
                            status: result.status,
                        },
                        inputRequests: result.inputRequests.map((row) => ({
                            requestId: row.requestId,
                            agentId: row.agentId,
                            agentName: row.agentName,
                            structuredInput: row.structuredInput,
                        })),
                        messages: result.messages.map((row) => (Object.assign({ id: row.id, runId: row.runId, replyId: row.replyId }, row.msg))),
                        spans: result.spans,
                    };
                }
                else {
                    throw new Error(`Run with id ${runId} not found`);
                }
            }
            catch (error) {
                console.error(error);
                throw error;
            }
        });
    }
    static changeRunStatus(runId, newStatus) {
        return __awaiter(this, void 0, void 0, function* () {
            try {
                const run = yield Run_1.RunTable.findOne({ where: { id: runId } });
                if (run) {
                    run.status = newStatus;
                    yield run.save();
                }
                else {
                    throw new Error(`Run with id ${runId} not found`);
                }
            }
            catch (error) {
                console.error(error);
                throw error;
            }
        });
    }
    static updateRunStatusAtBeginning() {
        return __awaiter(this, void 0, void 0, function* () {
            try {
                const runs = yield Run_1.RunTable.find({
                    where: [{ status: src_1.Status.RUNNING }, { status: src_1.Status.PENDING }],
                });
                for (const run of runs) {
                    const processExists = yield (0, utils_1.checkProcessByPid)(run.pid);
                    if (!processExists) {
                        run.status = src_1.Status.DONE;
                        yield run.save();
                    }
                }
            }
            catch (error) {
                console.error(error);
                throw error;
            }
        });
    }
    static getRunViewData() {
        return __awaiter(this, void 0, void 0, function* () {
            // Get run view data
            const runViewData = yield RunView_1.RunView.find();
            // Search four projects that are updated most recently
            const recentProjects = yield Run_1.RunTable.createQueryBuilder('run')
                .select('run.project', 'project')
                .addSelect('MAX(run.timestamp)', 'lastUpdateTime')
                .addSelect('COUNT(*)', 'runCount')
                // 按项目分组
                .groupBy('run.project')
                // 按最后更新时间降序排序
                .orderBy('lastUpdateTime', 'DESC')
                // 限制返回4个结果
                .limit(4)
                .getRawMany();
            return Object.assign(Object.assign({}, runViewData[0]), { recentProjects: recentProjects.map((project) => ({
                    name: project.project,
                    lastUpdateTime: project.lastUpdateTime,
                    runCount: parseInt(project.runCount),
                })) });
        });
    }
    static deleteRuns(runIds) {
        return __awaiter(this, void 0, void 0, function* () {
            const conditions = {
                id: (0, typeorm_1.In)(runIds),
            };
            const result = yield Run_1.RunTable.delete(conditions);
            return result.affected;
        });
    }
    static deleteProjects(projects) {
        return __awaiter(this, void 0, void 0, function* () {
            const conditions = {
                project: (0, typeorm_1.In)(projects),
            };
            const result = yield Run_1.RunTable.delete(conditions);
            return result.affected;
        });
    }
}
exports.RunDao = RunDao;
