const express = require('express');
const OSS = require('ali-oss');
const { STS } = require('ali-oss');
const { getCredential } = require('ali-oss/lib/common/signUtils');
const { getStandardRegion } = require('ali-oss/lib/common/utils/getStandardRegion');
const { policy2Str } = require('ali-oss/lib/common/utils/policy2Str');

const app = express();
const PORT = process.env.PORT || 8000; // 服务请求端口号

// 设置静态文件目录
app.use(express.static('templates'));

const GenerateSignature = async () => {
    // 初始化STS客户端
    let sts = new STS({
        accessKeyId: process.env.OSS_ACCESS_KEY_ID,  // 从环境变量中获取RAM用户的AccessKey ID
        accessKeySecret: process.env.OSS_ACCESS_KEY_SECRET // 从环境变量中获取RAM用户的AccessKey Secret
    });

    // 调用assumeRole接口获取STS临时访问凭证
    const result = await sts.assumeRole(process.env.OSS_STS_ROLE_ARN, '', '3600', 'yourRoleSessionName'); // 从环境变量中获取RAM角色ARN，并设置临时访问凭证有效期为3600秒，角色会话名称为yourRoleSessionName可自定义

    // 提取临时访问凭证中的AccessKeyId、AccessKeySecret和SecurityToken
    const accessKeyId = result.credentials.AccessKeyId;
    const accessKeySecret = result.credentials.AccessKeySecret;
    const securityToken = result.credentials.SecurityToken;

    // 初始化OSS Client
    const client = new OSS({
        bucket: 'examplebucket', // 请替换为目标Bucket名称
        region: 'cn-hangzhou', // 请替换为标Bucket所在地域
        accessKeyId,
        accessKeySecret,
        stsToken: securityToken,
        refreshSTSTokenInterval: 0,
        refreshSTSToken: async () => {
            const { accessKeyId, accessKeySecret, securityToken } = await client.getCredential();
            return { accessKeyId, accessKeySecret, stsToken: securityToken };
        },
    });

    // 创建表单数据Map
    const formData = new Map();

    // 设置签名过期时间为当前时间往后推10分钟 
    const date = new Date();
    const expirationDate = new Date(date);
    expirationDate.setMinutes(date.getMinutes() + 10);

    // 格式化日期为符合ISO 8601标准的UTC时间字符串格式
    function padTo2Digits(num) {
        return num.toString().padStart(2, '0');
    }
    function formatDateToUTC(date) {
        return (
            date.getUTCFullYear() +
            padTo2Digits(date.getUTCMonth() + 1) +
            padTo2Digits(date.getUTCDate()) +
            'T' +
            padTo2Digits(date.getUTCHours()) +
            padTo2Digits(date.getUTCMinutes()) +
            padTo2Digits(date.getUTCSeconds()) +
            'Z'
        );
    }
    const formattedDate = formatDateToUTC(expirationDate);
    // 设置上传回调URL，即回调服务器地址，用于处理应用服务器与OSS之间的通信。OSS会在文件上传完成后，把文件上传信息通过此回调URL发送给应用服务器。例如callbackUrl填写为https://oss-demo.aliyuncs.com:23450。

    // 生成x-oss-credential并设置表单数据
    const credential = getCredential(formattedDate.split('T')[0], getStandardRegion(client.options.region), client.options.accessKeyId);
    formData.set('x_oss_date', formattedDate);
    formData.set('x_oss_credential', credential);
    formData.set('x_oss_signature_version', 'OSS4-HMAC-SHA256');
  
    // 创建policy
    // 示例policy表单域只列举必填字段
    const policy = {
        expiration: expirationDate.toISOString(),
        conditions: [
            { 'bucket': 'examplebucket' }, // 请替换为目标Bucket名称
            { 'x-oss-credential': credential },
            { 'x-oss-signature-version': 'OSS4-HMAC-SHA256' },
            { 'x-oss-date': formattedDate },
        ],
    };

    // 如果存在STS Token，添加到策略和表单数据中
    if (client.options.stsToken) {
        policy.conditions.push({ 'x-oss-security-token': client.options.stsToken });
        formData.set('security_token', client.options.stsToken);
    }

    // 生成签名并设置表单数据
    const signature = client.signPostObjectPolicyV4(policy, date);
    formData.set('policy', Buffer.from(policy2Str(policy), 'utf8').toString('base64'));
    formData.set('signature', signature);
    const callback = {
      callbackUrl: 'http://oss-demo.aliyuncs.com:23450/callback',// 设置回调请求的服务器地址，例如http://oss-demo.aliyuncs.com:23450/callback。
      callbackBody:// 设置回调的内容，例如文件ETag、资源类型mimeType等。
      "filename=${object}&size=${size}&mimeType=${mimeType}&height=${imageInfo.height}&width=${imageInfo.width}",
      callbackBodyType: "application/x-www-form-urlencoded",//  设置回调的内容类型。    
    };
    // 返回表单数据
    return {
        host: `http://${client.options.bucket}.oss-${client.options.region}.aliyuncs.com`, 
        policy: Buffer.from(policy2Str(policy), 'utf8').toString('base64'),
        x_oss_signature_version: 'OSS4-HMAC-SHA256',
        x_oss_credential: credential,
        x_oss_date: formattedDate,
        signature: signature,
        dir: 'user-dir', // 指定上传到OSS的文件前缀
        callback: Buffer.from(JSON.stringify(callback)).toString("base64"),// 通过Buffer.from对JSON进行Base64编码。
        security_token: client.options.stsToken
    };
};

app.get('/get_post_signature_for_oss_upload', async (req, res) => {
    try {
        const result = await GenerateSignature();
        res.json(result); // 返回生成的签名数据
    } catch (error) {
        console.error('Error generating signature:', error);
        res.status(500).send('Error generating signature');
    }
});

app.listen(PORT, () => {
    console.log(`Server is running on http://127.0.0.1:${PORT}`);
});