import { chalk, alwaysLogWrapper, log, rmFiles, deleteEmptyDir, } from '@hlink/core';
import BaseSDK from './BaseSDK.js';
import configSDK from './ConfigSDK.js';
import * as exec from './exec.js';
import createSchedule, { cancelSchedule, hasSchedule, renameSchedule, } from './schedule.js';
import { main, prune } from '@hlink/core';
class TaskSDK extends BaseSDK {
    constructor() {
        super('tasks');
    }
    async add(c) {
        if (this.exist(c.name)) {
            throw new Error(`任务 ${c.name} 已存在`);
        }
        this.db.insert(c).value();
        await this.write();
        return true;
    }
    async update(prevName, c) {
        const task = this.get(prevName);
        if (!task) {
            throw new Error(`任务 ${prevName} 不存在`);
        }
        if (c.name !== prevName) {
            if (this.exist(c.name)) {
                throw new Error(`任务 ${c.name} 已存在`);
            }
            renameSchedule(prevName, c.name);
            this.db.removeById(prevName).value();
            this.db
                .insert({
                ...task,
                ...c,
            })
                .value();
        }
        else {
            this.db
                .upsert({
                ...task,
                ...c,
            })
                .value();
        }
        await this.write();
        return true;
    }
    async remove(name) {
        if (!this.exist(name)) {
            throw new Error(`任务 ${name} 不存在`);
        }
        if (await this.cancelSchedule(name)) {
            this.db.removeById(name).value();
            await this.write();
            return true;
        }
        return false;
    }
    get(name) {
        if (!this.exist(name)) {
            throw new Error(`任务 ${name} 不存在`);
        }
        return this.db.getById(name).value();
    }
    exist(name) {
        if (!name) {
            throw new Error('必须指定任务名称');
        }
        return !!this.db.getById(name).value();
    }
    getList() {
        const list = this.db.value();
        list.forEach((v) => {
            if (!!v.scheduleType && !hasSchedule(v.name)) {
                this.cancelSchedule(v.name, false);
            }
        });
        this.write();
        return this.db.value();
    }
    async getConfig(name) {
        const task = this.get(name);
        const allConfig = await configSDK.getOpt(task.config);
        let config;
        if (task.type === 'main') {
            config = allConfig;
        }
        else if (task.type === 'prune') {
            config = {
                withoutConfirm: false,
                pathsMapping: allConfig.pathsMapping,
                reverse: task.reverse,
                exclude: allConfig.exclude,
                include: allConfig.include,
                deleteDir: allConfig.deleteDir,
            };
        }
        else {
            throw new Error('未知的任务类型');
        }
        return {
            command: task.type,
            config,
        };
    }
    async start(name) {
        const result = await this.getConfig(name);
        const currentMonitor = exec.start(name, result.command, {
            ...result.config,
            usedBy: 'terminal',
        });
        currentMonitor.handleLog((d) => {
            log.error('任务执行出错', name);
            console.log(d);
        });
        return currentMonitor.original;
    }
    async run(name, log) {
        var _a;
        const result = await this.getConfig(name);
        let currentMonitor = exec.get(name);
        if (currentMonitor) {
            (_a = log.send) === null || _a === void 0 ? void 0 : _a.call(log, {
                output: alwaysLogWrapper.info(`任务 ${chalk.cyan(name)} 正在执行中..`),
                status: 'ongoing',
                type: result.command,
            });
        }
        else {
            currentMonitor = exec.start(name, result.command, result.config);
        }
        currentMonitor.handleLog((data) => {
            var _a;
            (_a = log.send) === null || _a === void 0 ? void 0 : _a.call(log, {
                output: data,
                status: 'ongoing',
                type: result.command,
            });
        });
        currentMonitor.original
            .then(async () => {
            var _a;
            (_a = log.send) === null || _a === void 0 ? void 0 : _a.call(log, {
                status: 'succeed',
                type: result.command,
                output: exec.getFiles(name)
                    ? alwaysLogWrapper.warn('请点击确认继续删除文件或者可以取消删除任务~')
                    : undefined,
                confirm: !!exec.getFiles(name),
            });
        })
            .catch((e) => {
            var _a, _b;
            console.log(e);
            if (e.killed) {
                return (_a = log.send) === null || _a === void 0 ? void 0 : _a.call(log, {
                    status: 'failed',
                    type: result.command,
                    output: alwaysLogWrapper.warn('已手动取消'),
                });
            }
            else {
                return (_b = log.send) === null || _b === void 0 ? void 0 : _b.call(log, {
                    status: 'failed',
                    type: result.command,
                    output: alwaysLogWrapper.error('任务执行出错，已终止'),
                });
            }
        })
            .then(() => {
            var _a;
            (_a = log.sendEnd) === null || _a === void 0 ? void 0 : _a.call(log);
        });
    }
    cancel(name) {
        return exec.cancel(name);
    }
    async confirmRemove(name, cancel = true) {
        if (cancel) {
            exec.clearFiles(name);
        }
        else {
            const deleteFiles = exec.getFiles(name);
            if (deleteFiles) {
                await rmFiles(deleteFiles);
                await deleteEmptyDir(deleteFiles);
            }
            exec.clearFiles(name);
        }
    }
    renameSchedule(preName, name) {
        if (renameSchedule(preName, name)) {
            return true;
        }
        return false;
    }
    async cancelSchedule(name, write = true) {
        const task = this.get(name);
        this.db
            .upsert({
            ...task,
            name,
            scheduleType: undefined,
            scheduleValue: undefined,
        })
            .value();
        if (cancelSchedule(name)) {
            if (write) {
                await this.write();
            }
            return true;
        }
        return false;
    }
    async createSchedule(option) {
        const { name, scheduleType, scheduleValue } = option;
        const task = this.get(option.name);
        this.db
            .upsert({
            ...task,
            name,
            scheduleType,
            scheduleValue,
        })
            .value();
        const taskConfig = await this.getConfig(name);
        let startTask = () => { };
        if (taskConfig.command === 'prune') {
            startTask = async () => {
                await prune({
                    ...taskConfig.config,
                    withoutConfirm: false,
                });
                console.log();
            };
        }
        else if (taskConfig.command === 'main') {
            startTask = async () => {
                await main(taskConfig.config);
                console.log();
            };
        }
        else {
            throw new Error('未知命令!');
        }
        if (createSchedule(option, startTask)) {
            await this.write();
            return true;
        }
        return false;
    }
}
export default new TaskSDK();
