import NodeCache from "node-cache";
import { randomBytes } from "crypto";
import { nanoid } from 'nanoid';

import { sha256 } from "../sub/crypto.js";
import { streamLifespan } from "../config.js";

const streamCache = new NodeCache({
    stdTTL: streamLifespan/1000,
    checkperiod: 10,
    deleteOnExpire: true
})

streamCache.on("expired", (key) => {
    streamCache.del(key);
})

const streamSalt = randomBytes(64).toString('hex');

export function createStream(obj) {
    let streamID = nanoid(),
        exp = Math.floor(new Date().getTime()) + streamLifespan,
        ghmac = sha256(`${streamID},${obj.service},${exp}`, streamSalt);

    if (!streamCache.has(streamID)) {
        streamCache.set(streamID, {
            id: streamID,
            service: obj.service,
            type: obj.type,
            urls: obj.u,
            filename: obj.filename,
            hmac: ghmac,
            exp: exp,
            isAudioOnly: !!obj.isAudioOnly,
            audioFormat: obj.audioFormat,
            time: obj.time ? obj.time : false,
            copy: !!obj.copy,
            mute: !!obj.mute,
            metadata: obj.fileMetadata ? obj.fileMetadata : false
        });
    } else {
        let streamInfo = streamCache.get(streamID);
        exp = streamInfo.exp;
        ghmac = streamInfo.hmac;
    }
    return `${process.env.apiURL}api/stream?t=${streamID}&e=${exp}&h=${ghmac}`;
}

export function verifyStream(id, hmac, exp) {
    try {
        let streamInfo = streamCache.get(id.toString());
        if (!streamInfo) return {
            error: "this download link has expired or doesn't exist. go back and try again!",
            status: 400
        }

        let ghmac = sha256(`${id},${streamInfo.service},${exp}`, streamSalt);
        if (String(hmac) === ghmac && String(exp) === String(streamInfo.exp) && ghmac === String(streamInfo.hmac)
            && Number(exp) > Math.floor(new Date().getTime())) {
            return streamInfo;
        }
        return {
            error: "i couldn't verify if you have access to this stream. go back and try again!",
            status: 401
        }
    } catch (e) {
        return { status: 500, body: { status: "error", text: "Internal Server Error" } };
    }
}
