const { rejects } = require('assert');

//global teleport variable
class Global_TP {
    constructor() {}
    STR_VALIDER(val) {
        if ((typeof val) === 'number') return false;
        if (val == undefined || val.trim().length === 0) return false;
        return true;
    }
    NUM_VALIDER(val) {
        if (val == undefined || (typeof val) != 'number') return false;
        return true;
    }
    DATE_VALIDER(val) {
        if (val == undefined || !(val instanceof Date) || isNaN(val)) return false;
        return true;
    }
    GET_CURRENTDATE() {
        const date = new Date(); // 현재 날짜 및 시간 객체 생성
    
        const year = date.getFullYear(); // 연도
        const month = String(date.getMonth() + 1).padStart(2, '0'); // 월 (0부터 시작하므로 +1 필요)
        const day = String(date.getDate()).padStart(2, '0'); // 일
    
        return `${year}-${month}-${day}`; // "YYYY-MM-DD" 형식으로 반환
    }
    GET_CURRENTDATE_TIME() {
        const date = new Date(); // 현재 날짜 및 시간 객체 생성
    
        const year = date.getFullYear(); // 연도
        const month = String(date.getMonth() + 1).padStart(2, '0'); // 월 (0부터 시작하므로 +1 필요)
        const day = String(date.getDate()).padStart(2, '0'); // 일
        let hour = String(date.getHours()).padStart(2, '0');
        let minute = String(date.getMinutes()).padStart(2, '0');
        let second = String(date.getSeconds()).padStart(2, '0');
        let ms = date.getMilliseconds();
    
        // "YYYY-MM-DD HH:MM:SS.ms" 형식으로 반환
        return `${year}-${month}-${day} ${hour}:${minute}:${second}.${ms}`;
    }
    GET_DAY_RANGES(startDate, endDate) {
        let result = [];
        let current = new Date(startDate);
    
        while (current <= endDate) {
            let c_year = current.getFullYear();
            let c_month = (current.getMonth() + 1).toString().padStart(2, '0'); // 1월은 0이므로 +1
            let c_day = current.getDate();
    
            let pre_dt = this.DATE_TO_STRING_HHMMSS(new Date(`${c_year}-${c_month}-${c_day} ${'00'}:${'00'}:${'00'}`));
            let next_dt = this.DATE_TO_STRING_HHMMSS(new Date(`${c_year}-${c_month}-${c_day} ${'23'}:${'59'}:${'59'}`));
    
            pre_dt = pre_dt.replace(" ", "T");
            next_dt = next_dt.replace(" ", "T");
            result.push({
                st: pre_dt,
                ed: next_dt,
            });
    
            current.setDate(current.getDate() + 1);
        }
    
        return result;
    }
    GET_MONTH_RANGES(startDate, endDate) {
        let result = [];
        startDate.setDate(1);
        endDate.setDate(1);
        let current = new Date(startDate);
    
        while (current <= endDate) {
            let year = current.getFullYear();
            let month = (current.getMonth() + 1).toString().padStart(2, '0'); // 1월은 0이므로 +1
    
            let month_st = new Date(`${year}-${month}`);
            month_st.setHours(0);
            month_st.setMinutes(0);
            month_st.setSeconds(0);
            let month_ed = new Date(year, month, 0);
            month_ed.setHours(23);
            month_ed.setMinutes(59);
            month_ed.setSeconds(59);
            result.push({
                st: this.DATE_TO_STRING_HHMMSS(month_st).replace(" ", "T"),
                ed: this.DATE_TO_STRING_HHMMSS(month_ed).replace(" ", "T"),
            });
    
            // 다음 달로 이동
            current.setMonth(current.getMonth() + 1);
        }
    
        return result;
    }
    DATE_TO_STRING(date) {
        let year = date.getFullYear();
        let month = String(date.getMonth() + 1).padStart(2, '0');
        let day = String(date.getDate()).padStart(2, '0');
    
        return `${year}-${month}-${day}`;
    }
    DATE_TO_STRING_HHMMSS(date) {
        let year = date.getFullYear();
        let month = String(date.getMonth() + 1).padStart(2, '0');
        let day = String(date.getDate()).padStart(2, '0');
        let hour = String(date.getHours()).padStart(2, '0');
        let minute = String(date.getMinutes()).padStart(2, '0');
        let second = String(date.getSeconds()).padStart(2, '0');
    
        return `${year}-${month}-${day} ${hour}:${minute}:${second}`;
    }
    CRYPTO_64_KEYGEN() {
        const crypto = require('crypto');
        return crypto.randomBytes(64).toString('hex');
    }
    GET_API_DEVICE_INFO(req) {
        let ret_info = undefined;
        if (req) {
            const UAParser = require('ua-parser-js');
            const userAgent = req.headers['user-agent'];
            const uapars = new UAParser();
            ret_info = uapars.setUA(userAgent).getResult();
        }
        return ret_info;
    }
    READ_AES256CBC_KEY(path) {
        const fs = require('fs');
        
        // 🔹 바이너리 파일에서 데이터 읽기
        let binaryData = undefined;
        let secretKeyFromFile = undefined;
        let ivFromFile = undefined;
        try {
            binaryData = fs.readFileSync(path);
            // 🔹 secretKey(32바이트)와 IV(16바이트) 분리
            secretKeyFromFile = binaryData.subarray(0, 32) // 256비트 키
            ivFromFile = binaryData.subarray(32, 48) // 128비트 IV
        }
        catch(erroror) {
            const crypto = require('crypto');
            let secKey_byte = crypto.randomBytes(32);
            let ivKey_byte = crypto.randomBytes(16);
            secretKeyFromFile = secKey_byte;
            ivFromFile = ivKey_byte;

            _GTP.WRITE_AES256CBC_KEY(path, secKey_byte, ivKey_byte);
        }

        return {
            secretKey: secretKeyFromFile,
            ivKey: ivFromFile
        }
    }
    WRITE_AES256CBC_KEY(path, secKey, ivKey) {
        const fs = require('fs');
        const crypto = require('crypto');

        // ✅ 256비트(32바이트) secretKey & 128비트(16바이트) IV 생성
        let secretKey = crypto.randomBytes(32);
        let iv = crypto.randomBytes(16);

        if (secKey) secretKey = secKey;
        if (ivKey) iv = ivKey

        // 🔹 secretKey + IV를 바이너리 데이터로 병합
        const binaryData = Buffer.concat([secretKey, iv]);

        // 🔹 바이너리 파일로 저장
        if (!fs.existsSync(path)) {
            fs.writeFileSync(path, binaryData, { mode: 0o666 }); // 권한 666으로 설정하여 모든 사용자 읽기/쓰기 가능
            // console.log("✅ license_key.bin 파일이 생성되었습니다.");
        }
        // fs.writeFileSync(path, binaryData); //keys.bin
        // console.log("🔑 AES 키가 바이너리 파일(keys.bin)에 저장되었습니다.");
    }
    GET_AES256CBC_ENCRYPT(json, keyInfo) {
        const crypto = require('crypto');
        const jsonString = JSON.stringify(json);
        const cipher = crypto.createCipheriv('aes-256-cbc', keyInfo.secretKey, keyInfo.ivKey);
        let encrypted = cipher.update(jsonString, 'utf-8', 'hex');
        encrypted += cipher.final('hex');
        return encrypted;
    }
    GET_AES256CBC_DECRYPT(encData, keyInfo) {
        const crypto = require('crypto');

        const decipher = crypto.createDecipheriv('aes-256-cbc', keyInfo.secretKey, keyInfo.ivKey);
        let decrypted = decipher.update(encData, 'hex', 'utf-8');
        decrypted += decipher.final('utf-8');
        return JSON.parse(decrypted);
    }
    FIRMWARE_VERSION_NUMBER(verString) {
        const versionParts = verString.split(".");

        return Number(versionParts[0]) * 100000 + Number(versionParts[1]) * 1000 + Number(versionParts[2])
    }
    CapitalizeFirstLetter(str) {
        if (!str) return ''; // 빈 문자열 체크
        return str.charAt(0).toUpperCase() + str.slice(1);
    }
    FloorTo3Digits(num) {
        return Math.floor(num * 1000) / 1000;
    }
    BCRYPT_HASH(password) {
        const bcrypt = require('bcrypt');
        const saltRounds = 10;
        password = String(password);
        const hProm = new Promise((resolve, reject) => {
            bcrypt.hash(password, saltRounds, async (error, hash) => { 
                if (error) reject(error);
                resolve(hash)
            })
        })
        
        return hProm;
    }
    BCRYPT_COMPARE(loginPw, hashedDBPw) {
        const bcrypt = require('bcrypt');
        loginPw = String(loginPw);
        const hProm = new Promise((resolve, reject) => {
            bcrypt.compare(loginPw, hashedDBPw, function(err, res) {
                if (err) reject(err);
                resolve(res);
            })
        })
        return hProm;
        
    }
}

module.exports = Global_TP;