import crypto from 'node:crypto'

const dataIsEmpty = !localStorage.tws_data || localStorage.tws_data == ''

class Aes {
    static randomIv() {
        return crypto.randomBytes(12)
    }
    static normalizeKey(key: string, keyLength = 32) {
        const hash = crypto.createHash('sha256')
        hash.update(key)
        const keyBuffer = hash.digest()
        return keyLength ? keyBuffer.subarray(0, keyLength) : keyBuffer
    }
    static encrypt(data: string, key: string) {
        const iv = this.randomIv()
        return Buffer.concat([iv, crypto.createCipheriv("aes-256-gcm", this.normalizeKey(key), iv).update(data)]).toString('hex')
    }
    static decrypt(data: string, key: string) {
        const buffer = Buffer.from(data, 'hex')
        const iv = buffer.subarray(0, 12)
        return crypto.createDecipheriv("aes-256-gcm", this.normalizeKey(key), iv).update(buffer.subarray(12)).toString()
    }
}

// 尽可能防止被窃取, 虽然理论上还是会被窃取
const key = crypto.createHash('sha256').update(location.host + '_TWS_姐姐_' + navigator.userAgent).digest().toString('base64')

if (dataIsEmpty) localStorage.tws_data = Aes.encrypt('{}', key)

let _data_cached
try {
    _data_cached = JSON.parse(Aes.decrypt(localStorage.tws_data, key))
} catch (e) {
    console.warn("数据解密失败, 使用空数据...", e)
    _data_cached = {}
}

type IData = {
    refresh_token?: string
    split_sizes: number[]
    apply(): void
    access_token?: string
    device_id: string
}

declare global {
    interface Window {
        data?: IData
    }
}

const data = new Proxy({} as IData, {
    get(_obj, k) {
        if (k == '_cached') return _data_cached
        if (k == 'apply') return () => localStorage.tws_data = Aes.encrypt(JSON.stringify(_data_cached), key)
        return _data_cached[k]
    },
    set(_obj, k, v) {
        if (k == '_cached') return false
        _data_cached[k] = v
        return true
    }
})

if (new URL(location.href).searchParams.get('export_data') == 'true') {
    window.data = data
    console.warn("警告: 将 data 暴露到 window 有可能会导致令牌泄露!")
}

export default data
