/**
 * wa_license.js — WebAssets Licensing Engine (Phase 1)
 * Product: Justdial Data Extractor
 * Phase 1: Extension Hardening (Offline stub — API wired in Phase 3)
 *
 * Architecture: ALL auth decisions are made here in the background
 * service worker. popup.js / content.js NEVER decide — they only ASK.
 */

// ─── CONFIG ──────────────────────────────────────────────────────────────────
const WA_CONFIG = {
    PRODUCT_ID:   'justdial',
    PRODUCT_NAME: 'Justdial Data Extractor',
    API_URL:      'https://webassets.tech/wp-json/webassets/v1/validate', // Phase 3: live
    // Encrypt key seed (unique per product — DO NOT share across extensions)
    KEY_SEED:     'wa_justdial_prod_9x2m',
};

// ─── DEVICE ID ───────────────────────────────────────────────────────────────
async function wa_getDeviceId() {
    return new Promise((resolve) => {
        chrome.storage.local.get(['__wa_did'], (r) => {
            if (r.__wa_did) { resolve(r.__wa_did); return; }
            const id = 'WA-' + Date.now().toString(36) + '-' + Math.random().toString(36).slice(2, 10).toUpperCase();
            chrome.storage.local.set({ __wa_did: id });
            resolve(id);
        });
    });
}

// ─── AES-GCM CRYPTO ──────────────────────────────────────────────────────────
async function wa_deriveKey(deviceId) {
    const raw = WA_CONFIG.KEY_SEED + ':' + deviceId;
    const keyMaterial = await crypto.subtle.importKey(
        'raw', new TextEncoder().encode(raw).slice(0, 32),
        { name: 'AES-GCM' }, false, ['encrypt', 'decrypt']
    );
    return keyMaterial;
}

async function wa_encrypt(plaintext, deviceId) {
    try {
        const key = await wa_deriveKey(deviceId);
        const iv  = crypto.getRandomValues(new Uint8Array(12));
        const enc = await crypto.subtle.encrypt(
            { name: 'AES-GCM', iv },
            key,
            new TextEncoder().encode(plaintext)
        );
        return JSON.stringify({ iv: Array.from(iv), d: Array.from(new Uint8Array(enc)) });
    } catch(e) { return null; }
}

async function wa_decrypt(cipherJSON, deviceId) {
    try {
        const obj = JSON.parse(cipherJSON);
        const key = await wa_deriveKey(deviceId);
        const dec = await crypto.subtle.decrypt(
            { name: 'AES-GCM', iv: new Uint8Array(obj.iv) },
            key,
            new Uint8Array(obj.d)
        );
        return new TextDecoder().decode(dec);
    } catch(e) { return null; } // tampered or invalid → null → locked
}

// ─── TOKEN STORE ─────────────────────────────────────────────────────────────
async function wa_saveToken(tokenObj, deviceId) {
    tokenObj.product = WA_CONFIG.PRODUCT_ID; // Force inject product ID for cross-extension isolation
    const payload  = JSON.stringify(tokenObj);
    const encrypted = await wa_encrypt(payload, deviceId);
    if (!encrypted) return false;
    await chrome.storage.local.set({ __wa_tok: encrypted, __wa_exp: tokenObj.expiresAt });
    return true;
}

async function wa_loadToken(deviceId) {
    return new Promise((resolve) => {
        chrome.storage.local.get(['__wa_tok', '__wa_exp'], async (r) => {
            if (!r.__wa_tok) { resolve(null); return; }
            const plain = await wa_decrypt(r.__wa_tok, deviceId);
            if (!plain)   { resolve(null); return; } // decryption failed → tampered
            try {
                const obj = JSON.parse(plain);
                // Validate product match — prevents cross-extension token reuse
                if (obj.product !== WA_CONFIG.PRODUCT_ID) { resolve(null); return; }
                resolve(obj);
            } catch(e) { resolve(null); }
        });
    });
}

async function wa_clearToken() {
    await chrome.storage.local.remove(['__wa_tok', '__wa_exp']);
}

// ─── LICENSE CHECK (called from background.js) ───────────────────────────────
async function wa_isLicenseValid() {
    const deviceId = await wa_getDeviceId();
    const tokenObj = await wa_loadToken(deviceId);
    if (!tokenObj) return false;
    const now = Date.now();
    if (tokenObj.expiresAt <= now) {
        await wa_clearToken(); // auto-wipe on expiry
        return false;
    }
    return true;
}

// ─── BACKGROUND HEARTBEAT POLLING ──────────────────────────────────────────
async function wa_checkServerStatus() {
    try {
        const deviceId = await wa_getDeviceId();
        const tokenObj = await wa_loadToken(deviceId);
        if (!tokenObj || !tokenObj.originalCode) return false;

        const baseUrl = WA_CONFIG.API_URL.replace('/validate', '');
        const response = await fetch(`${baseUrl}/status`, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({
                code: tokenObj.originalCode,
                device_id: deviceId
            })
        });

        const data = await response.json();
        
        // If server explicitly says the token is invalid (revoked or expired), kill it.
        if (data && data.valid === false) {
            console.warn("Server marked token as invalid. Revoking local access.");
            await wa_clearToken();
            
            // Notify UI to lock immediately if open
            chrome.runtime.sendMessage({ action: "LOCK_UI" }).catch(() => {});
            return false;
        }
        
        return true;
    } catch (e) {
        // If server is unreachable, we fail OPEN (trust the local token until expiry)
        console.warn("Heartbeat ping failed (offline or server error). Trusting local token.");
        return true; 
    }
}

// ─── ACTIVATION (validate with server or test code) ──────────────────────────
async function wa_activate(userCode) {
    const deviceId = await wa_getDeviceId();



    // ── Phase 3: Real API call (active when backend is live) ──
    try {
        const resp = await fetch(WA_CONFIG.API_URL, {
            method:  'POST',
            headers: { 'Content-Type': 'application/json' },
            body:    JSON.stringify({ code: userCode, device_id: deviceId, product: WA_CONFIG.PRODUCT_ID }),
        });
        if (!resp.ok && resp.status !== 403) {
            return { success: false, message: 'Server error. Please try again later.' };
        }
        const data = await resp.json();
        if (data.success) {
            const expiresAtMs = new Date(data.expires_at).getTime();
            const saved = await wa_saveToken({
                token: data.token,
                expiresAt: expiresAtMs,
                originalCode: userCode,
                product: WA_CONFIG.PRODUCT_ID
            }, deviceId);
            return saved
                ? { success: true, message: data.message || 'Access granted.', expiresAt: expiresAtMs }
                : { success: false, message: 'Storage error.' };
        }
        return { success: false, message: data.message || 'Invalid code.' };
    } catch(e) {
        return { success: false, message: 'Network error. Check your internet connection.' };
    }
}

// ─── TAMPER TRAPS (decoy functions — DO NOT rename or remove) ────────────────
function bypassLicense()  { wa_clearToken(); console.warn('[WA] Tamper detected.'); }
function unlockExtension(){ wa_clearToken(); }
function skipLicense()    { wa_clearToken(); }
function forceUnlock()    { wa_clearToken(); }

// ─── EXPIRY INFO ─────────────────────────────────────────────────────────────
async function wa_getExpiryMs() {
    return new Promise((resolve) => {
        chrome.storage.local.get(['__wa_exp'], (r) => resolve(r.__wa_exp || 0));
    });
}

// ─── EXPORTS (used by background.js message handler) ─────────────────────────
// All functions prefixed with wa_ are available globally in the service worker
