import fs from 'fs'
import path from 'path';
import {
    fileURLToPath
} from 'url';
import ini from 'ini'
import axios from "axios";
import {decryptFile} from "./fileCrypto.js";

class Ql {
    constructor() {
        console.log(`Readme: 请先初始化config.ini,打开qitoqito_psyduck/config文件夹,将demo.ini重命名为config.ini\n        设置QINGLONG_ClientId和QINGLONG_ClientSecret(前面;符号要去掉才能正常解析)\n        如需使用脚本分身,请先自行创建分类ini\n        以京东为例,在指定的iniPath目录(默认qitoqito_psyduck/config)自行创建jd.ini\n\n        [jd_checkCookie]\n        map=jd_task_checkCookie\n        ;title=自定义脚本名\n        ;crontab=自定义定时(6 6 6 6 6)\n\n        将上述节点代码复制到jd.ini,jd_checkCookie就能映射到jd_task_checkCookie脚本\n`)
        const dirpath = fileURLToPath(
            import.meta.url);
        const abspath = path.dirname(dirpath)
        let iniText = fs.readFileSync(`${abspath}/config/config.ini`, 'UTF-8')
        let obj = ini.parse(iniText)
        this.panelJson = JSON.parse(fs.readFileSync(`${abspath}/config/panel.json`, 'UTF-8'))
        this.env = obj.env
        if (this.env.QINGLONG_ClientId) {
            this.config = {
                baseURL: this.env.QINGLONG_BaseUrl || 'http://127.0.0.1:5700',
                clientId: this.env.QINGLONG_ClientId,
                clientSecret: this.env.QINGLONG_ClientSecret
            };
        }
        else {
            this.config = null
        }
        this.token = null
    }

    // 获取 token
    async getToken() {
        try {
            const response = await axios.get(`${this.config.baseURL}/open/auth/token`, {
                params: {
                    client_id: this.config.clientId,
                    client_secret: this.config.clientSecret
                }
            });
            this.token = response.data.data.token;
            return this.token;
        } catch (error) {
            console.error('[Error] 获取qinglong token失败', error);
            throw error;
        }
    }

    async setEnvs(data) {
        const token = this.token
        try {
            const response = await axios.put(`${this.config.baseURL}/open/envs`, data, {
                headers: {
                    'Authorization': `Bearer ${token}`
                }
            });
            return response.data;
        } catch (error) {
            console.error('[Error] 更新环境变量失败:', error);
        }
    }

    // 获取环境变量
    async getEnvs(search = null) {
        const token = this.token
        try {
            const response = await axios.get(`${this.config.baseURL}/open/envs?searchValue=${search}`, {
                headers: {
                    'Authorization': `Bearer ${token}`
                }
            });
            return response.data.data;
        } catch (error) {
            console.error('[Error] 获取qinglong环境变量失败:', error);
            throw error;
        }
    }

    // 添加环境变量
    async addEnv(name, value, remarks = '') {
        const token = this.token
        try {
            const response = await axios.post(`${this.config.baseURL}/open/envs`, [{
                name,
                value,
                remarks
            }], {
                headers: {
                    'Authorization': `Bearer ${token}`
                }
            });
            return response.data;
        } catch (error) {
            console.error('[Error] 添加qinglong环境变量失败');
            throw error;
        }
    }

    // 删除环境变量
    async deleteEnv(envId) {
        const token = this.token
        try {
            const response = await axios.delete(`${this.config.baseURL}/open/envs`, {
                data: [envId],
                headers: {
                    'Authorization': `Bearer ${token}`
                }
            });
            return response.data;
        } catch (error) {
            console.error('[Error] 删除qinglong环境变量失败');
            throw error;
        }
    }

    // 获取定时任务列表
    async getCrons() {
        const token = this.token
        try {
            const response = await axios.get(`${this.config.baseURL}/open/crons`, {
                headers: {
                    'Authorization': `Bearer ${token}`
                }
            });
            return response.data.data;
        } catch (error) {
            console.error('[Error] 获取qinglong定时任务失败');
            throw error;
        }
    }

    // 运行任务
    async runCrons(cronIds) {
        const token = this.token
        try {
            const response = await axios.put(`${this.config.baseURL}/open/crons/run`, cronIds, {
                headers: {
                    'Authorization': `Bearer ${token}`
                }
            });
            return response.data;
        } catch (error) {
            console.error('[Error] 运行qinglong任务失败');
            throw error;
        }
    }

    // 获取任务日志
    async getCronLogs(cronId) {
        const token = this.token
        try {
            const response = await axios.get(`${this.config.baseURL}/open/crons/${cronId}/log`, {
                headers: {
                    'Authorization': `Bearer ${token}`
                }
            });
            return response.data.data;
        } catch (error) {
            console.error('获取任务日志失败:', error);
            throw error;
        }
    }

    async addCron(command) {
        const token = this.token
        try {
            const response = await axios.post(`${this.config.baseURL}/open/crons`, command, {
                headers: {
                    'Authorization': `Bearer ${token}`
                }
            });
            return response.data;
        } catch (error) {
            console.error('[Error] 创建定时任务失败:', error);
            throw error;
        }
    }

    async delCron(command) {
        const token = this.token
        try {
            const response = await axios.delete(`${this.config.baseURL}/open/crons`, {
                data: [command.id || command._id],
                headers: {
                    'Authorization': `Bearer ${token}`
                }
            });
            return response.data;
        } catch (error) {
            console.error('[Error] 删除定时任务失败:', error);
            throw error;
        }
    }

    async wait(t) {
        return new Promise(e => setTimeout(e, t))
    }

    async create() {
        if (!this.config) {
            console.log("请先初始化config.ini,并设置青龙ClientID和ClientSecret")
            return
        }
        await this.getToken()
        let dirpath = fileURLToPath(
            import.meta.url);
        let abspath = path.dirname(dirpath)
        let iniPath = this.env.iniPath || `${abspath}/config`
        let crons = await this.getCrons()
        let data = {}
        let cronData = crons.data || crons
        let label = crons.data ? true : false
        for (let i of cronData) {
            let command = i.command.match(/task\s*qitoqito_psyduck\/(\w+\.js)/)
            if (command) {
                let script = command[1]
                data[script] = {
                    name: i.name,
                    schedule: i.schedule,
                    id: i.id,
                    command: i.command
                }
            }
        }
        let dicts = {}
        let dir = fs.readdirSync(`${abspath}/parse`);
        let panelJson = this.panelJson
        let fileList = []
        dir.forEach(async function(item, index) {
            let config = panelJson.script[item] || {}
            let delList = config.delete || []
            let stat = fs.lstatSync(`${abspath}/parse/` + item)
            if (stat.isDirectory() === true) {
                for (let script of fs.readdirSync(`${abspath}/parse/${item}`)) {
                    if (script.match(/\w+\_\w+\_\w/)) {
                        fileList.push(`${abspath}/parse/${item}/${script}`)
                    }
                }
            }
        }.bind(this))
        await this.wait(1000)
        for (let filePath of fileList) {
            await decryptFile(filePath, filePath)
        }
        dir.forEach(async function(item, index) {
            let config = panelJson.script[item] || {}
            let delList = config.delete || []
            let stat = fs.lstatSync(`${abspath}/parse/` + item)
            if (stat.isDirectory() === true) {
                if (fs.existsSync(`${iniPath}/${item}.ini`)) {
                    let iniText = fs.readFileSync(`${iniPath}/${item}.ini`, 'UTF-8')
                    let obj = ini.parse(iniText)
                    for (let filename in obj) {
                        if (obj[filename].map) {
                            let map = obj[filename].map
                            try {
                                let imp = await import (`${abspath}/parse/${item}/${map}.js`)
                                let psyDuck = new imp.Main()
                                psyDuck.env.delayTo = this.env.delayTo || null
                                let crontab = obj[filename].crontab || psyDuck.crontab()
                                let title = obj[filename].title || `${psyDuck.profile.title}分身`
                                let code = `
import path from 'path';
import {fileURLToPath, pathToFileURL} from 'url';
!(async () => {
    let dirpath = fileURLToPath(import.meta.url).replace('.swap','');
    let abspath = path.dirname(dirpath)
    let filename = dirpath.match(/(\\w+)\\.js/)[1]
    let type = filename.split('_')[0]
    if (['js', 'jx', 'jr', 'jw'].includes(type)) {
        type = 'jd'
    }
    let length = process.argv.length
    let params = {
        filename: "${map}",
        mapping: filename,
        title: "${title}",
    }
    if (length > 2) {
        for (let i = 2; i < length; i++) {
            let key = process.argv[i].match(/^-\\w+$/)
            if (key) {
                params[key[0].substr(1)] = process.argv[i + 1]
            }
        }
    }
    let jsPath = pathToFileURL(\`\${abspath}/parse/\${type}/${map}.js\`).href
    let psyDuck = await import (jsPath)
    let main = new psyDuck.Main()
    await main.init(params)
})().catch((e) => {
    if (e == 'End') {
        console.log("End")
    }else{
        console.log(e)
    }
    process.exit()
})`
                                fs.writeFile(`${abspath}/${filename}.js`, code, function(err, data) {
                                    if (err) {
                                        throw err;
                                    }
                                    console.log(`🐯‍❄️ 写入成功: ${filename}.js`)
                                })
                                if (!data[`${filename}.js`]) {
                                    dicts[`${filename}.js`] = {
                                        name: `PsyDuck_${title}`,
                                        schedule: crontab,
                                        command: `task qitoqito_psyduck/${filename}.js`,
                                        // labels: label ? [`PsyDuck`] : ''
                                    }
                                    if (label) {
                                        dicts[`${filename}.js`].labels = [`PsyDuck`]
                                    }
                                }
                            } catch (e) {
                                console.log(e)
                            }
                        }
                    }
                }
                for (let script of fs.readdirSync(`${abspath}/parse/${item}`)) {
                    if (delList.includes(script)) {
                        for (let obj of cronData) {
                            if (obj.command.includes(script)) {
                                console.log(`🦊🐼 删除任务:`, script)
                                await this.delCron(obj)
                            }
                        }
                    }
                    else {
                        try {
                            if (script.match(/\w+\_\w+\_\w/)) {
                                let imp = await
                                    import (`${abspath}/parse/${item}/${script}`)
                                let psyDuck = new imp.Main()
                                psyDuck.env.delayTo = this.env.delayTo || null
                                let crontab = psyDuck.crontab()
                                let code = `
import path from 'path';
import {fileURLToPath, pathToFileURL} from 'url';
!(async () => {
    let dirpath = fileURLToPath(import.meta.url).replace('.swap','');
    let abspath = path.dirname(dirpath)
    let filename = dirpath.match(/(\\w+)\\.js/)[1]
    let type = filename.split('_')[0]
    if (['js', 'jx', 'jr', 'jw'].includes(type)) {
        type = 'jd'
    }
    let length = process.argv.length
    let params = {
        filename
    }
    if (length > 2) {
        for (let i = 2; i < length; i++) {
            let key = process.argv[i].match(/^-\\w+$/)
            if (key) {
                params[key[0].substr(1)] = process.argv[i + 1]
            }
        }
    }
    let jsPath = pathToFileURL(\`\${abspath}/parse/\${type}/\${filename}.js\`).href
    let psyDuck = await import (jsPath)
    let main = new psyDuck.Main()
    await main.init(params)
})().catch((e) => {
    if (e == 'End') {
        console.log("End")
    }else{
        console.log(e)
    }
    process.exit()
})`
                                fs.writeFile(`${abspath}/${script}`, code, function(err, data) {
                                    if (err) {
                                        throw err;
                                    }
                                    console.log(`🐯‍❄️ 写入成功: ${script}`)
                                })
                                if (!data[script]) {
                                    dicts[script] = {
                                        name: `PsyDuck_${psyDuck.profile.title}`,
                                        schedule: crontab,
                                        command: `task qitoqito_psyduck/${script}`,
                                        // labels: label ? [`PsyDuck`] : ''
                                    }
                                    if (label) {
                                        dicts[script].labels = [`PsyDuck`]
                                    }
                                }
                            }
                        } catch (e) {
                            console.log(`🐽🐽️ 写入失败: ${script}`)
                        }
                    }
                }
            }
        }.bind(this))
        await this.wait(10000)
        let commands = Object.values(dicts)
        for (let i in dicts) {
            try {
                let add = await this.addCron(dicts[i])
                if (add.data.name) {
                    console.log('🐯‍❄️ 任务添加成功: ', i)
                }
            } catch (e) {
                console.log('🐽🐽️ 任务添加失败: ', i)
            }
        }
    }
}

let qinglong = new Ql()
qinglong.create()
