/**
 * 非标接口模块
 */

import { logger } from "mslib"
import { ApiResponse } from "./TyApiCommon"
import Contants, { IS_PROD, IS_TEST } from "./Contants";
import * as crypto from 'crypto'
import { ApiError } from "./Errors";
import { IocConfigProvider, NonStandardApiConfig } from "./Config";

let defaults = {
    key: 'Keytop:1234567812345678!',
    iv: '20210723'
}

let nonstandard_api_config: NonStandardApiConfig = IocConfigProvider.getNonStandardApiConfig();

/**
 * 非标接口3des加解密工具
 */
export class Des3Utils {
    /**
     * 解密
     */
    static decrypt(data: object | string, key = nonstandard_api_config?.key || defaults.key, iv = nonstandard_api_config?.iv || defaults.iv): object {
        let decipher = crypto.createDecipheriv('des-ede3-cbc', key, iv);
        let decrypted = decipher.update(typeof data === 'object' ? data['data'] : data, 'base64', 'utf8');
        decrypted += decipher.final('utf8');

        let obj = JSON.parse(decrypted);
        if (typeof data === 'object' && data['imageInfo']) {
            obj['imageInfo'] = data['imageInfo'];
        }

        return obj;
    }

    /**
     * 加密
     */
    static encrypt(data: object | string, key = nonstandard_api_config?.key || defaults.key, iv = nonstandard_api_config?.iv || defaults.iv): { data: string, imageInfo?: string } {
        let dataWrap: any = {};
        if (data['imageInfo']) dataWrap['imageInfo'] = data['imageInfo'];

        let cipher = crypto.createCipheriv('des-ede3-cbc', key, iv);
        let encrypted = Buffer.concat([cipher.update(Buffer.from(typeof data === 'string' ? data : JSON.stringify(data))), cipher.final()]);

        dataWrap['data'] = encrypted.toString('base64');

        return dataWrap;
    }

    /**
     * 随机生成24位的字符串
     */
    static generateKey() {
        return crypto.getDiffieHellman('modp14').generateKeys('base64').substring(0, 24);
    }
}

/**
 * 非标接口装饰器
 * 
 * 对参数进行解密,异常捕获,记录日志,如果出现异常则自动返回失败报文
 * @param description 服务描述，仅为日志输出
 */
export function Service(description?: string, config?: {
    /**
     * 是否记录接口调用(成功)日志
     */
    isLog?: boolean
}): MethodDecorator {
    return function (target: Object, propertyKey: string, descriptor: PropertyDescriptor) {
        logger.info(`${Contants.SS_SERVICE_BASE_URL}/${Contants.P_ID}.${target.constructor.name}/1.0`, description);

        let method = descriptor.value;

        descriptor.value = async function (...args) {
            let response;
            let _error;

            try {
                let is_secure = (IS_PROD || IS_TEST) && !(IS_TEST && args[0]?.secure === false);
                if (is_secure) {
                    args[0] = Des3Utils.decrypt(args[0], nonstandard_api_config?.key || defaults.key, nonstandard_api_config?.iv || defaults.iv);
                }

                response = await method.apply(this, args);
            } catch (error) {
                response = IS_PROD ? ApiResponse.failed('服务器异常') : ApiResponse.failed(error instanceof Error ? error.message : error.toString());
                _error = error;
            }

            if (_error)
                logger.error(`${description || '非标接口'}'${target.constructor.name}'出现异常,请求参数:${JSON.stringify(args, replaceBase64Str)},返回值:${JSON.stringify(response)}\n>>>>>`, _error instanceof ApiError ? _error.toString() : _error);
            else {
                if (!(config?.isLog === false)) logger.info(`${description || '非标接口'}'${target.constructor.name}',请求参数:${JSON.stringify(args, replaceBase64Str)},返回值:${JSON.stringify(response)}`);
            }

            return response;
        }
    }
}

function replaceBase64Str(key, value) {
    if (key === 'imageInfo' || (typeof value === 'string' && value.startsWith('data:'))) return '[base64Str]';
    return value;
}