const express = require('express')
const Logger = require('./Logger')
const requestLog = require('./requestLog')
const path = require('path')
const fs = require('fs')
const forge = require('node-forge')
const crypto = require('crypto')
const { BaseStdResponse } = require("../BaseStdResponse")

class API {
    constructor() {
        this.router = express.Router()
        this.namespace = ''
        this.path = ''
        this.method = 'get'
        this.encrypt = true

        this.privateKey = fs.readFileSync(path.join(__dirname, '../keys/private_key.pem'), 'utf8')

        this.logger = new Logger()
        this.requestLog = new requestLog()
    }

    noEncrypt() {
        this.encrypt = false
    }

    setPath(path) {
        this.path = path
    }

    setMethod(method) {
        this.method = method.toLowerCase()
    }

    getRouter() {
        return this.router
    }

    async onRequest(req, res) {
        throw new Error('onRequest方法未实现')
    }

    /**
     * 解密数据：使用 RSA 解密 AES 密钥，再用 AES 解密数据
     */
    decryptPayload(req, res, next) {
        if(!this.encrypt)
            return next()
        try {
            let encryptedKey, encryptedData
            if (this.method === 'get') {
                encryptedKey = req.query.b
                encryptedData = req.query.a
            } else {
                encryptedKey = req.body.b
                encryptedData = req.body.a
            }

            if (!encryptedKey || !encryptedData)
                return res.json({
                    ...BaseStdResponse.MISSING_PARAMETER,
                    msg: '参数错误。请刷新页面或更新客户端版本'
                })

            // 1. 解密 AES 密钥（RSA）
            const privateKey = forge.pki.privateKeyFromPem(this.privateKey)
            const aesKey = privateKey.decrypt(forge.util.decode64(encryptedKey), 'RSAES-PKCS1-V1_5')

            // 2. 解密数据（AES）
            const decipher = crypto.createDecipheriv('aes-128-ecb', Buffer.from(aesKey, 'utf8'), null)
            decipher.setAutoPadding(true)
            let decrypted = decipher.update(encryptedData, 'base64', 'utf8')
            decrypted += decipher.final('utf8')
            decrypted = JSON.parse(decrypted)

            const time = Date.now()
            if (Math.abs(time - decrypted.time) > 3 * 60 * 1000)
                return res.json({
                    ...BaseStdResponse.ERR,
                    msg: '请检查计算机时间是否正确！'
                })

            decrypted.aesKey = aesKey

            if (this.method === 'get')
                req.query = decrypted
            else
                req.body = decrypted

            const requestId = req.headers['x-request-id'] || ''
            res.setHeader('X-Request-ID', requestId)

            next()
        } catch (err) {
            console.error('解密失败:', err)
            return res.json({
                ...BaseStdResponse.ERR,
                msg: '参数错误'
            })
        }
    }

    aesEncrypt(data, req) {
        let aesKey
        if (this.method === 'get')
            aesKey = req.query.aesKey
        else
            aesKey = req.body.aesKey

        const cipher = crypto.createCipheriv('aes-128-ecb', Buffer.from(aesKey, 'utf8'), null)
        cipher.setAutoPadding(true)
        let encryptedData = cipher.update(JSON.stringify(data), 'utf8', 'base64')
        encryptedData += cipher.final('base64')
        return encryptedData
    }

    setupRoute() {
        this.router[this.method](this.path, this.decryptPayload.bind(this), async (req, res) => {
            // 拦截返回值统一加密
            const originalJson = res.json.bind(res)
            res.json = (data) => {
                this.requestLog.insertLog(req, JSON.parse(JSON.stringify(data)), this.namespace, this.method, this.path)

                if(this.encrypt && data.data) {
                    data.b = this.aesEncrypt(data.data, req)
                    delete data.data
                }

                return originalJson(data)
            }

            try {
                await this.onRequest(req, res)
            } catch (err) {
                this.logger.error(`接口处理异常: ${err.stack || err}`)
                if (!res.headersSent) {
                    return res.json({
                        ...BaseStdResponse.ERR,
                        msg: err?.code === 'RUNTIME_CONFIG_NOT_FOUND'
                            ? `${err.key || '运行时配置'} 暂未配置或未启用`
                            : '服务处理失败，请稍后再试'
                    })
                }
            }
        })
    }
}

module.exports = API
