chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
    if (request.action === 'analyzeToken') {
        analyzeToken(
            request.mint,
            request.padreDA,
            request.devStats,
            request.padreDevMintedCount,
            request.padreDevSoldStrict,
            request.padreDevHoldingPct,
            request.clientFingerprint,
            request.userId,
            request.uniqueUserId
        ).then(sendResponse).catch((err) => {
            console.error("PRC: analyzeToken unhandled error:", err?.message || err);
            sendResponse({ success: false, error: "Analysis failed unexpectedly" });
        });
        return true;
    }
    if (request.action === 'getFlagState') {
        getFlagCount(request.creator, request.clientFingerprint, request.userId, request.uniqueUserId).then(sendResponse);
        return true;
    }
    if (request.action === 'flagCreator') {
        flagCreator(request.creator, request.mint, request.tokenSymbol, request.tokenName, request.clientFingerprint, request.userId, request.uniqueUserId).then(sendResponse);
        return true;
    }
    if (request.action === 'submitAppeal') {
        submitAppeal(request.creator, request.wallet, request.description).then(sendResponse);
        return true;
    }
    if (request.action === 'getUserStats') {
        getUserStats(request.clientFingerprint, request.userId, request.uniqueUserId).then(sendResponse);
        return true;
    }
    if (request.action === 'syncCloudStats') {
        syncCloudStats(
            request.clientFingerprint,
            request.userId,
            request.uniqueUserId,
            request.statsPayload,
            request.statsUpdatedAt
        ).then(sendResponse);
        return true;
    }
    if (request.action === 'restoreCloudStats') {
        restoreCloudStats(
            request.clientFingerprint,
            request.userId,
            request.recoveryCode
        ).then(sendResponse);
        return true;
    }
    if (request.action === 'getSealState') {
        getSealState(request.mint, request.creator, request.tokenSymbol, request.tokenAgeDays, request.clientFingerprint, request.userId).then(sendResponse);
        return true;
    }
    if (request.action === 'voteSealOfHermeto') {
        voteSealOfHermeto(request.mint, request.creator, request.tokenSymbol, request.clientFingerprint, request.userId).then(sendResponse);
        return true;
    }
});

// Manual activation via extension icon
chrome.action.onClicked.addListener((tab) => {
    const tabUrl = String(tab?.url || '');
    if (tabUrl.match(/https?:\/\/trade\.padre\.gg\//i)) {
        chrome.tabs.sendMessage(tab.id, { action: 'toggleUI' }, () => {
            if (chrome.runtime.lastError) {
                // No receiver on this tab/frame; ignore to avoid uncaught promise errors.
                console.debug("PRC: toggleUI skipped:", chrome.runtime.lastError.message);
            }
        });
    }
});

const API_BASE = "https://hermeto-black-book.vercel.app";
const HELIUS_API_KEY = ""; // USER: Add your Helius API key here for premium analysis
let cachedUserIP = null;
let cachedUserIPAt = 0;
const SOLANA_ADDRESS_RE = /([1-9A-HJ-NP-Za-km-z]{32,44})/;
const FLAG_CACHE_TTL_MS = 60000;
const flagCountCache = new Map();
const flagCountInFlight = new Map();

function parseRuggerThreshold(data, fallback = 5) {
    const raw = data?.ruggerThreshold ?? data?.threshold ?? data?.flagThreshold ?? data?.scammerThreshold;
    const parsed = parseInt(raw, 10);
    return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
}

function invalidateFlagCacheForCreator(creatorAddress) {
    if (!creatorAddress) return;
    const prefix = `${creatorAddress}|`;
    for (const key of flagCountCache.keys()) {
        if (key.startsWith(prefix)) flagCountCache.delete(key);
    }
    for (const key of flagCountInFlight.keys()) {
        if (key.startsWith(prefix)) flagCountInFlight.delete(key);
    }
}

async function fetchWithTimeout(resource, options = {}) {
    const { timeout = 8000 } = options;
    const controller = new AbortController();
    const id = setTimeout(() => controller.abort(), timeout);
    try {
        const response = await fetch(resource, {
            ...options,
            signal: controller.signal
        });
        clearTimeout(id);
        return response;
    } catch (error) {
        clearTimeout(id);
        throw error;
    }
}



async function getUserIP() {
    const now = Date.now();
    if (cachedUserIP && now - cachedUserIPAt < 10 * 60 * 1000) {
        return cachedUserIP;
    }
    try {
        const resp = await fetchWithTimeout('https://api.ipify.org?format=json', { timeout: 3000 });
        if (resp.ok) {
            const data = await resp.json();
            cachedUserIP = data.ip;
            cachedUserIPAt = now;
            return data.ip;
        }
    } catch (err) {
        console.warn("PRC: Could not fetch IP, using fallback", err);
    }
    return "unknown-ip";
}

async function getOrCreateInstallId() {
    const key = 'prcInstallId';
    const data = await chrome.storage.local.get([key]);
    if (data[key]) return data[key];
    const id = (crypto && crypto.randomUUID) ? crypto.randomUUID() : `${Date.now()}-${Math.random().toString(36).slice(2)}`;
    await chrome.storage.local.set({ [key]: id });
    return id;
}

function normalizeInstallIdInput(input) {
    if (!input) return null;
    const clean = String(input).trim();
    if (!clean) return null;
    return clean.slice(0, 64);
}

function normalizeUniqueUserIdInput(input) {
    if (!input) return null;
    const clean = String(input).trim();
    if (!clean) return null;
    return clean.slice(0, 64);
}

function normalizeClientFingerprint(fp) {
    if (!fp || typeof fp !== 'object') return null;
    return {
        userAgent: String(fp.userAgent || '').slice(0, 256),
        platform: String(fp.platform || '').slice(0, 64),
        language: String(fp.language || '').slice(0, 32),
        timezone: String(fp.timezone || '').slice(0, 64),
        screen: String(fp.screen || '').slice(0, 32),
        cores: Number.isFinite(Number(fp.cores)) ? Number(fp.cores) : 0
    };
}

async function getIdentityPayload(clientFingerprint, options = {}) {
    const includeIP = options.includeIP === true;
    const preferredInstallId = normalizeInstallIdInput(options.preferredInstallId);
    const preferredUniqueUserId = normalizeUniqueUserIdInput(options.preferredUniqueUserId);
    const installId = preferredInstallId || await getOrCreateInstallId();
    const uniqueUserId = preferredUniqueUserId || installId;
    return {
        userIP: includeIP ? await getUserIP() : null,
        installId,
        uniqueUserId,
        fingerprint: normalizeClientFingerprint(clientFingerprint)
    };
}

function normalizeCreatorAddress(input) {
    if (!input) return null;
    const text = String(input).trim();
    if (!text || text === "Unknown") return null;
    const match = text.match(SOLANA_ADDRESS_RE);
    return match ? match[1] : null;
}

function parseNumericLoose(value) {
    if (value === null || value === undefined) return 0;
    if (typeof value === 'number') return Number.isFinite(value) ? value : 0;
    const raw = String(value).trim();
    if (!raw) return 0;
    const cleaned = raw.replace(/[^0-9.-]/g, '');
    const num = Number(cleaned);
    return Number.isFinite(num) ? num : 0;
}

function parseBooleanFlag(value, fallback = false) {
    if (value === null || value === undefined) return Boolean(fallback);
    if (typeof value === 'boolean') return value;
    if (typeof value === 'number') return value === 1;
    const text = String(value).trim().toLowerCase();
    if (!text) return Boolean(fallback);
    if (['1', 'true', 'yes', 'y', 'on'].includes(text)) return true;
    if (['0', 'false', 'no', 'n', 'off', 'null', 'undefined'].includes(text)) return false;
    return Boolean(fallback);
}

// --- ON-CHAIN GROUND TRUTH (SOLANA RPC) ---
const SOLANA_RPCS = [
    "https://api.mainnet-beta.solana.com",
    "https://solana-api.projectserum.com",
    "https://solana-mainnet.rpc.extrnode.com",
    "https://solana-rpc.publicnode.com",
    "https://api.mainnet.solana.com",
    "https://solana-mainnet.gateway.tatum.io"
];
const RPC_HEALTH_DECAY_MS = 60 * 1000;
const RPC_BASE_BACKOFF_MS = 500;
const RPC_MAX_BACKOFF_MS = 12000;
const rpcHealth = new Map();

function sleep(ms) {
    return new Promise((resolve) => setTimeout(resolve, ms));
}

function isExpectedRpcError(err) {
    if (!err) return false;
    return err.name === 'AbortError' || err.name === 'DOMException' || String(err.message || '').toLowerCase().includes('timeout');
}

function getRpcHealthState(url) {
    const now = Date.now();
    const prev = rpcHealth.get(url) || { failCount: 0, nextAllowedAt: 0, lastFailureAt: 0 };
    if (prev.failCount > 0 && (now - prev.lastFailureAt) > RPC_HEALTH_DECAY_MS) {
        const decayed = { ...prev, failCount: Math.max(0, prev.failCount - 1) };
        rpcHealth.set(url, decayed);
        return decayed;
    }
    return prev;
}

function markRpcSuccess(url) {
    const prev = getRpcHealthState(url);
    rpcHealth.set(url, { failCount: Math.max(0, prev.failCount - 1), nextAllowedAt: 0, lastFailureAt: prev.lastFailureAt });
}

function markRpcFailure(url, severe = false) {
    const now = Date.now();
    const prev = getRpcHealthState(url);
    const nextFail = prev.failCount + (severe ? 2 : 1);
    const exp = Math.min(6, nextFail);
    const jitter = Math.floor(Math.random() * 450);
    const backoff = Math.min(RPC_MAX_BACKOFF_MS, (RPC_BASE_BACKOFF_MS * (2 ** exp)) + jitter);
    rpcHealth.set(url, { failCount: nextFail, nextAllowedAt: now + backoff, lastFailureAt: now });
}

function buildRpcOrder() {
    const now = Date.now();
    return [...SOLANA_RPCS]
        .map((url) => ({ url, h: getRpcHealthState(url) }))
        .sort((a, b) => {
            const aReady = a.h.nextAllowedAt <= now ? 0 : 1;
            const bReady = b.h.nextAllowedAt <= now ? 0 : 1;
            if (aReady !== bReady) return aReady - bReady;
            if (a.h.failCount !== b.h.failCount) return a.h.failCount - b.h.failCount;
            if (a.h.nextAllowedAt !== b.h.nextAllowedAt) return a.h.nextAllowedAt - b.h.nextAllowedAt;
            return Math.random() - 0.5;
        })
        .map((x) => x.url);
}

function isRateLimitPayload(data) {
    const msg = String(data?.error?.message || '').toLowerCase();
    return msg.includes('429') || msg.includes('rate') || msg.includes('too many');
}

async function solanaRPC(method, params, options = {}) {
    const timeout = Number(options.timeout) > 0 ? Number(options.timeout) : 1300;
    const maxRounds = Number(options.maxRounds) > 0 ? Number(options.maxRounds) : 1;
    const totalTimeout = Number(options.totalTimeout) > 0 ? Number(options.totalTimeout) : 4500;
    const startedAt = Date.now();
    const deadline = startedAt + totalTimeout;

    for (let round = 0; round < maxRounds; round++) {
        if (Date.now() >= deadline) return null;
        const ordered = buildRpcOrder();
        for (const rpcUrl of ordered) {
            if (Date.now() >= deadline) return null;
            const state = getRpcHealthState(rpcUrl);
            const now = Date.now();
            if (state.nextAllowedAt > now) continue;
            try {
                const remaining = deadline - Date.now();
                if (remaining <= 250) return null;
                const effectiveTimeout = Math.max(350, Math.min(timeout, remaining));
                const resp = await fetchWithTimeout(rpcUrl, {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({ jsonrpc: "2.0", id: 1, method, params }),
                    timeout: effectiveTimeout
                });
                if (!resp.ok) {
                    markRpcFailure(rpcUrl, resp.status === 429 || resp.status >= 500);
                    continue;
                }
                const data = await resp.json();
                if (data?.error) {
                    markRpcFailure(rpcUrl, isRateLimitPayload(data));
                    continue;
                }
                if (Object.prototype.hasOwnProperty.call(data || {}, 'result')) {
                    markRpcSuccess(rpcUrl);
                    return data.result;
                }
                markRpcFailure(rpcUrl, false);
            } catch (err) {
                markRpcFailure(rpcUrl, true);
                if (!isExpectedRpcError(err)) {
                    console.warn(`PRC: RPC warning [${method}] via ${rpcUrl}:`, err?.message || err);
                }
            }
        }
        if (round < maxRounds - 1) {
            const jitter = Math.floor(Math.random() * 250);
            const waitMs = Math.min((RPC_BASE_BACKOFF_MS * (2 ** round)) + jitter, Math.max(0, deadline - Date.now()));
            if (waitMs > 0) await sleep(waitMs);
        }
    }
    return null;
}

async function getDevHoldingsOnChain(creator, mint) {
    const creatorAddress = normalizeCreatorAddress(creator);
    if (!creatorAddress) return null;
    const result = await solanaRPC("getTokenAccountsByOwner", [
        creatorAddress,
        { mint: mint },
        { encoding: "jsonParsed" }
    ], { timeout: 900, totalTimeout: 2600, maxRounds: 1 });
    if (!result || !result.value || result.value.length === 0) return 0;

    // Sum up all accounts (usually just one)
    let total = 0;
    for (const acc of result.value) {
        total += acc.account.data.parsed.info.tokenAmount.uiAmount || 0;
    }
    return total;
}

const DEV_FLOW_CACHE_TTL_MS = 2 * 60 * 1000;
const devFlowCache = new Map();
const CREATOR_MINT_COUNT_CACHE_TTL_MS = 10 * 60 * 1000;
const creatorMintCountCache = new Map();
const CREATOR_MINT_COUNT_STORE_KEY = 'prcCreatorMintedCountsV1';
const MINT_INIT_CREATOR_CACHE_TTL_MS = 10 * 60 * 1000;
const mintInitCreatorCache = new Map();
const FLAGGED_CREATORS_STORE_KEY = 'prcUserFlaggedCreatorsV1';
const flaggedCreatorsLocalCache = new Map(); // creator -> timestamp
const NON_WALLET_PROGRAM_IDS = new Set([
    '11111111111111111111111111111111',
    'ComputeBudget111111111111111111111111111111',
    'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA',
    'TokenzQdYh6JrE5b5hXCTZVEkR92pT9XyM54q9WavH',
    'ATokenGPvbdGVxr1QhX6jvaf7fW4g7wYB1iBf9Y2f',
    'metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s'
]);

function getUiAmount(tokenAmountObj) {
    if (!tokenAmountObj) return 0;
    const ui = Number(tokenAmountObj.uiAmount);
    if (Number.isFinite(ui)) return ui;
    const uiStr = Number(tokenAmountObj.uiAmountString);
    if (Number.isFinite(uiStr)) return uiStr;
    const amountRaw = Number(tokenAmountObj.amount);
    const decimals = Number(tokenAmountObj.decimals);
    if (Number.isFinite(amountRaw) && Number.isFinite(decimals)) {
        return amountRaw / (10 ** decimals);
    }
    return 0;
}

function computeOwnerMintDelta(meta, owner, mint) {
    const pre = new Map();
    const post = new Map();
    (meta?.preTokenBalances || []).forEach((b) => {
        if (b?.owner === owner && b?.mint === mint) {
            pre.set(Number(b.accountIndex), getUiAmount(b.uiTokenAmount));
        }
    });
    (meta?.postTokenBalances || []).forEach((b) => {
        if (b?.owner === owner && b?.mint === mint) {
            post.set(Number(b.accountIndex), getUiAmount(b.uiTokenAmount));
        }
    });

    const idxSet = new Set([...pre.keys(), ...post.keys()]);
    let incoming = 0;
    let outgoing = 0;
    idxSet.forEach((idx) => {
        const preAmt = Number(pre.get(idx)) || 0;
        const postAmt = Number(post.get(idx)) || 0;
        const delta = postAmt - preAmt;
        if (delta > 0) incoming += delta;
        else if (delta < 0) outgoing += Math.abs(delta);
    });

    return { incoming, outgoing };
}

function extractMintFromParsedInstruction(ins, accountKeys = []) {
    if (!ins) return null;
    const parsedType = String(ins?.parsed?.type || '').toLowerCase();
    const isInitMint = parsedType === 'initializemint' || parsedType === 'initializemint2' || parsedType === 'initializemintcloseauthority';
    if (!isInitMint) return null;

    const mintFromInfo = normalizeCreatorAddress(ins?.parsed?.info?.mint);
    if (mintFromInfo) return mintFromInfo;

    const accounts = Array.isArray(ins?.accounts) ? ins.accounts : [];
    if (accounts.length === 0) return null;
    const first = accounts[0];
    if (typeof first === 'string') return normalizeCreatorAddress(first);
    if (typeof first === 'number' && Array.isArray(accountKeys)) {
        const keyObj = accountKeys[first];
        const key = typeof keyObj === 'string' ? keyObj : keyObj?.pubkey;
        return normalizeCreatorAddress(key);
    }
    return null;
}

function extractAccountKeyAddress(keyEntry) {
    if (typeof keyEntry === 'string') return normalizeCreatorAddress(keyEntry);
    if (keyEntry && typeof keyEntry === 'object') {
        return normalizeCreatorAddress(keyEntry.pubkey || keyEntry.address || null);
    }
    return null;
}

function extractMessageSignerAddresses(message) {
    if (!message || typeof message !== 'object') return [];
    const accountKeys = Array.isArray(message.accountKeys) ? message.accountKeys : [];
    const requiredSigners = Number(message?.header?.numRequiredSignatures) || 0;
    const out = [];
    const seen = new Set();
    for (let i = 0; i < accountKeys.length; i += 1) {
        const entry = accountKeys[i];
        const addr = extractAccountKeyAddress(entry);
        if (!addr || seen.has(addr)) continue;
        let isSigner = false;
        if (entry && typeof entry === 'object' && Object.prototype.hasOwnProperty.call(entry, 'signer')) {
            isSigner = Boolean(entry.signer);
        } else {
            isSigner = i < requiredSigners;
        }
        if (!isSigner) continue;
        seen.add(addr);
        out.push(addr);
    }
    return out;
}

function pickCreatorFromInitInstruction(ins, message, accountKeys = []) {
    const signerAddresses = extractMessageSignerAddresses(message);
    const feePayer = extractAccountKeyAddress(Array.isArray(accountKeys) ? accountKeys[0] : null);
    const mintAuthority = normalizeCreatorAddress(ins?.parsed?.info?.mintAuthority);

    if (mintAuthority && signerAddresses.includes(mintAuthority)) return mintAuthority;
    if (feePayer && signerAddresses.includes(feePayer)) return feePayer;
    if (signerAddresses.length > 0) return signerAddresses[0];
    if (mintAuthority) return mintAuthority;
    if (feePayer) return feePayer;
    return null;
}

function pickCreatorFromMessageSigners(message, accountKeys = []) {
    const signerAddresses = extractMessageSignerAddresses(message)
        .filter((addr) => addr && !NON_WALLET_PROGRAM_IDS.has(String(addr)));
    if (signerAddresses.length > 0) return signerAddresses[0];
    const feePayer = extractAccountKeyAddress(Array.isArray(accountKeys) ? accountKeys[0] : null);
    if (feePayer && !NON_WALLET_PROGRAM_IDS.has(String(feePayer))) return feePayer;
    return null;
}

async function getCreatorFromMintInitOnChain(mintAddress) {
    const mint = normalizeCreatorAddress(mintAddress);
    if (!mint) return null;

    const now = Date.now();
    const cached = mintInitCreatorCache.get(mint);
    if (cached && (now - cached.at) < MINT_INIT_CREATOR_CACHE_TTL_MS) {
        return cached.value || null;
    }

    try {
        const signatures = [];
        let before = undefined;
        for (let page = 0; page < 7 && signatures.length < 280; page += 1) {
            const opts = before ? { limit: 40, before } : { limit: 40 };
            const res = await solanaRPC("getSignaturesForAddress", [mint, opts], {
                timeout: 900,
                totalTimeout: 2500,
                maxRounds: 1
            });
            if (!Array.isArray(res) || res.length === 0) break;
            signatures.push(...res);
            before = res[res.length - 1]?.signature;
            if (!before || res.length < 40) break;
        }

        const unique = Array.from(new Set(signatures.map((s) => s?.signature).filter(Boolean)));
        if (unique.length === 0) {
            mintInitCreatorCache.set(mint, { at: now, value: null });
            return null;
        }

        // getSignaturesForAddress is newest->oldest; we want oldest first for mint init tx.
        const oldestFirst = unique.reverse().slice(0, 72);
        let oldestSignerFallback = null;
        for (const sig of oldestFirst) {
            const tx = await solanaRPC("getTransaction", [
                sig,
                { encoding: "jsonParsed", maxSupportedTransactionVersion: 0 }
            ], { timeout: 900, totalTimeout: 2400, maxRounds: 1 });
            if (!tx?.transaction?.message) continue;
            const message = tx.transaction.message;
            const accountKeys = Array.isArray(message.accountKeys) ? message.accountKeys : [];
            const outer = Array.isArray(message.instructions) ? message.instructions : [];
            const innerGroups = Array.isArray(tx?.meta?.innerInstructions) ? tx.meta.innerInstructions : [];
            if (!oldestSignerFallback) {
                const signerHint = pickCreatorFromMessageSigners(message, accountKeys);
                if (signerHint) {
                    oldestSignerFallback = { creator: signerHint, signature: sig, source: 'oldest_mint_signer' };
                }
            }

            let initInstruction = null;
            for (const ins of outer) {
                const minted = extractMintFromParsedInstruction(ins, accountKeys);
                if (minted && String(minted).toLowerCase() === String(mint).toLowerCase()) {
                    initInstruction = ins;
                    break;
                }
            }
            if (!initInstruction) {
                for (const group of innerGroups) {
                    const arr = Array.isArray(group?.instructions) ? group.instructions : [];
                    for (const ins of arr) {
                        const minted = extractMintFromParsedInstruction(ins, accountKeys);
                        if (minted && String(minted).toLowerCase() === String(mint).toLowerCase()) {
                            initInstruction = ins;
                            break;
                        }
                    }
                    if (initInstruction) break;
                }
            }
            if (!initInstruction) continue;

            const creator = pickCreatorFromInitInstruction(initInstruction, message, accountKeys);
            if (creator) {
                const value = { creator, signature: sig, source: 'mint_init_instruction' };
                mintInitCreatorCache.set(mint, { at: now, value });
                return value;
            }
        }
        if (oldestSignerFallback?.creator) {
            mintInitCreatorCache.set(mint, { at: now, value: oldestSignerFallback });
            return oldestSignerFallback;
        }
    } catch (err) {
        console.warn("PRC: getCreatorFromMintInitOnChain failed:", err?.message || err);
    }

    mintInitCreatorCache.set(mint, { at: now, value: null });
    return null;
}

async function getCreatorMintedTokenCountOnChain(creator) {
    const creatorAddress = normalizeCreatorAddress(creator);
    if (!creatorAddress) return null;

    const now = Date.now();
    const cached = creatorMintCountCache.get(creatorAddress);
    if (cached && (now - cached.at) < CREATOR_MINT_COUNT_CACHE_TTL_MS) {
        return cached.value;
    }

    try {
        const signatures = [];
        let before = undefined;
        for (let page = 0; page < 6 && signatures.length < 180; page++) {
            const opts = before ? { limit: 30, before } : { limit: 30 };
            const res = await solanaRPC("getSignaturesForAddress", [creatorAddress, opts], { timeout: 850, totalTimeout: 2200, maxRounds: 1 });
            if (!Array.isArray(res) || res.length === 0) break;
            signatures.push(...res);
            before = res[res.length - 1]?.signature;
            if (!before || res.length < 30) break;
        }

        const uniqueSigs = Array.from(new Set(signatures.map((s) => s?.signature).filter(Boolean))).slice(0, 180);
        const minted = new Set();

        for (const sig of uniqueSigs) {
            const tx = await solanaRPC("getTransaction", [
                sig,
                { encoding: "jsonParsed", maxSupportedTransactionVersion: 0 }
            ], { timeout: 850, totalTimeout: 2200, maxRounds: 1 });
            if (!tx?.transaction?.message) continue;
            const accountKeys = Array.isArray(tx.transaction.message.accountKeys) ? tx.transaction.message.accountKeys : [];
            const outer = Array.isArray(tx.transaction.message.instructions) ? tx.transaction.message.instructions : [];
            const innerGroups = Array.isArray(tx?.meta?.innerInstructions) ? tx.meta.innerInstructions : [];

            for (const ins of outer) {
                const mintAddr = extractMintFromParsedInstruction(ins, accountKeys);
                if (mintAddr) minted.add(mintAddr);
            }
            for (const group of innerGroups) {
                const arr = Array.isArray(group?.instructions) ? group.instructions : [];
                for (const ins of arr) {
                    const mintAddr = extractMintFromParsedInstruction(ins, accountKeys);
                    if (mintAddr) minted.add(mintAddr);
                }
            }
        }

        const value = minted.size;
        creatorMintCountCache.set(creatorAddress, { at: now, value });
        return value;
    } catch (err) {
        console.warn("PRC: getCreatorMintedTokenCountOnChain failed:", err?.message || err);
        return null;
    }
}

async function getCreatorMintedCountFromStore(creator) {
    const creatorAddress = normalizeCreatorAddress(creator);
    if (!creatorAddress) return null;
    try {
        const cached = creatorMintCountCache.get(creatorAddress);
        if (cached && Number.isFinite(Number(cached.value)) && Number(cached.value) > 0) {
            return Number(cached.value);
        }
        const stored = await chrome.storage.local.get([CREATOR_MINT_COUNT_STORE_KEY]);
        const map = (stored?.[CREATOR_MINT_COUNT_STORE_KEY] && typeof stored[CREATOR_MINT_COUNT_STORE_KEY] === 'object')
            ? stored[CREATOR_MINT_COUNT_STORE_KEY]
            : {};
        const val = Number(map?.[creatorAddress]);
        if (Number.isFinite(val) && val > 0) {
            creatorMintCountCache.set(creatorAddress, { at: Date.now(), value: val });
            return val;
        }
    } catch (err) {
        console.warn("PRC: getCreatorMintedCountFromStore failed:", err?.message || err);
    }
    return null;
}

async function setCreatorMintedCountInStore(creator, count) {
    const creatorAddress = normalizeCreatorAddress(creator);
    const nextCount = Number(count);
    if (!creatorAddress || !Number.isFinite(nextCount) || nextCount <= 0) return;
    try {
        const stored = await chrome.storage.local.get([CREATOR_MINT_COUNT_STORE_KEY]);
        const map = (stored?.[CREATOR_MINT_COUNT_STORE_KEY] && typeof stored[CREATOR_MINT_COUNT_STORE_KEY] === 'object')
            ? stored[CREATOR_MINT_COUNT_STORE_KEY]
            : {};
        const current = Number(map?.[creatorAddress]) || 0;
        const best = Math.max(current, Math.floor(nextCount));
        map[creatorAddress] = best;
        // Keep storage bounded.
        const keys = Object.keys(map);
        if (keys.length > 2500) {
            for (let i = 0; i < keys.length - 2500; i++) delete map[keys[i]];
        }
        await chrome.storage.local.set({ [CREATOR_MINT_COUNT_STORE_KEY]: map });
        creatorMintCountCache.set(creatorAddress, { at: Date.now(), value: best });
    } catch (err) {
        console.warn("PRC: setCreatorMintedCountInStore failed:", err?.message || err);
    }
}

async function getIsCreatorFlaggedLocally(creator) {
    const creatorAddress = normalizeCreatorAddress(creator);
    if (!creatorAddress) return false;
    try {
        if (flaggedCreatorsLocalCache.has(creatorAddress)) return true;
        const stored = await chrome.storage.local.get([FLAGGED_CREATORS_STORE_KEY]);
        const map = (stored?.[FLAGGED_CREATORS_STORE_KEY] && typeof stored[FLAGGED_CREATORS_STORE_KEY] === 'object')
            ? stored[FLAGGED_CREATORS_STORE_KEY]
            : {};
        if (map[creatorAddress]) {
            flaggedCreatorsLocalCache.set(creatorAddress, map[creatorAddress]);
            return true;
        }
    } catch (err) {
        console.warn("PRC: getIsCreatorFlaggedLocally failed:", err?.message || err);
    }
    return false;
}

async function setIsCreatorFlaggedLocally(creator) {
    const creatorAddress = normalizeCreatorAddress(creator);
    if (!creatorAddress) return;
    const now = Date.now();
    flaggedCreatorsLocalCache.set(creatorAddress, now); // Update memory cache IMMEDIATELY to prevent race conditions
    try {
        const stored = await chrome.storage.local.get([FLAGGED_CREATORS_STORE_KEY]);
        const map = (stored?.[FLAGGED_CREATORS_STORE_KEY] && typeof stored[FLAGGED_CREATORS_STORE_KEY] === 'object')
            ? stored[FLAGGED_CREATORS_STORE_KEY]
            : {};
        map[creatorAddress] = now;
        // Keep storage bounded
        const keys = Object.keys(map);
        if (keys.length > 3000) {
            for (let i = 0; i < keys.length - 3000; i++) delete map[keys[i]];
        }
        await chrome.storage.local.set({ [FLAGGED_CREATORS_STORE_KEY]: map });
    } catch (err) {
        console.warn("PRC: setIsCreatorFlaggedLocally failed:", err?.message || err);
    }
}

async function getRecentDevSellSignalOnChain(creator, mint) {
    const creatorAddress = normalizeCreatorAddress(creator);
    if (!creatorAddress || !mint) return { hasSell: false, hasData: false, incoming: 0, outgoing: 0, examinedTx: 0 };

    const cacheKey = `${creatorAddress}|${mint}`;
    const now = Date.now();
    const cached = devFlowCache.get(cacheKey);
    if (cached && (now - cached.at) < DEV_FLOW_CACHE_TTL_MS) {
        return cached.value;
    }

    try {
        const startedAt = Date.now();
        const FLOW_TIME_BUDGET_MS = 2800;
        const timeExceeded = () => (Date.now() - startedAt) > FLOW_TIME_BUDGET_MS;
        const tokenAccountsRes = await solanaRPC("getTokenAccountsByOwner", [
            creatorAddress,
            { mint },
            { encoding: "jsonParsed" }
        ], { timeout: 850, totalTimeout: 2200, maxRounds: 1 });
        const tokenAccounts = Array.isArray(tokenAccountsRes?.value) ? tokenAccountsRes.value : [];

        const accountPubkeys = tokenAccounts
            .map((acc) => acc?.pubkey)
            .filter(Boolean)
            .slice(0, 3);

        const fetchSignaturesPaged = async (address, perPage = 18, maxTotal = 60) => {
            const out = [];
            let before = undefined;
            for (let page = 0; page < 4 && out.length < maxTotal; page++) {
                if (timeExceeded()) break;
                const opts = before ? { limit: perPage, before } : { limit: perPage };
                const res = await solanaRPC("getSignaturesForAddress", [address, opts], { timeout: 800, totalTimeout: 2000, maxRounds: 1 });
                if (!Array.isArray(res) || res.length === 0) break;
                out.push(...res);
                before = res[res.length - 1]?.signature;
                if (!before || res.length < perPage) break;
            }
            return out.slice(0, maxTotal);
        };

        const signatureSet = new Set();

        // Token-account history (high precision for this mint)
        for (const tokenAcc of accountPubkeys) {
            if (timeExceeded()) break;
            const sigs = await fetchSignaturesPaged(tokenAcc, 16, 36);
            sigs.forEach((s) => {
                if (s?.signature) signatureSet.add(s.signature);
            });
        }

        // Creator wallet history (captures cases where token account got closed/migrated)
        const creatorSigs = await fetchSignaturesPaged(creatorAddress, 18, tokenAccounts.length > 0 ? 44 : 60);
        creatorSigs.forEach((s) => {
            if (s?.signature) signatureSet.add(s.signature);
        });

        const signatures = Array.from(signatureSet).slice(0, 64);
        let incoming = 0;
        let outgoing = 0;
        let examinedTx = 0;
        let relevantTx = 0;

        for (const sig of signatures) {
            if (timeExceeded()) break;
            const tx = await solanaRPC("getTransaction", [
                sig,
                { encoding: "jsonParsed", maxSupportedTransactionVersion: 0 }
            ], { timeout: 800, totalTimeout: 1900, maxRounds: 1 });
            if (!tx?.meta) continue;
            examinedTx += 1;
            const delta = computeOwnerMintDelta(tx.meta, creatorAddress, mint);
            if (delta.incoming > 0 || delta.outgoing > 0) relevantTx += 1;
            incoming += delta.incoming;
            outgoing += delta.outgoing;
        }

        const hasData = relevantTx > 0;
        const netOutflow = outgoing - incoming;
        const MIN_FLOW_ABS = 0.001;
        const MIN_NET_ABS = 0.001;
        const flowRatio = incoming > 0 ? (outgoing / incoming) : (outgoing > 0 ? 999 : 0);
        const meaningfulOutgoing = outgoing > MIN_FLOW_ABS;
        const majorOutgoing = incoming > 0 ? outgoing >= (incoming * 0.65) : outgoing > 0.01;
        const strongNetOut = netOutflow > MIN_NET_ABS && (flowRatio >= 0.65 || incoming === 0);
        const repeatedOutflow = relevantTx >= 3 && outgoing > (MIN_FLOW_ABS * 2) && netOutflow > MIN_NET_ABS;
        // Consider sell evidence if there is meaningful outgoing and one of:
        // 1) strong net outflow, 2) major outgoing vs total in + net outflow, 3) repeated outflow tx.
        const hasSell = hasData && meaningfulOutgoing && (
            strongNetOut ||
            (majorOutgoing && netOutflow > MIN_NET_ABS) ||
            repeatedOutflow
        );
        const value = { hasSell, hasData, incoming, outgoing, netOutflow, flowRatio, examinedTx, relevantTx };
        devFlowCache.set(cacheKey, { at: now, value });
        return value;
    } catch (err) {
        console.warn("PRC: getRecentDevSellSignalOnChain failed:", err?.message || err);
        return { hasSell: false, hasData: false, incoming: 0, outgoing: 0, examinedTx: 0 };
    }
}

const COOLDOWN_MS = 6 * 60 * 60 * 1000; // 6 hours

async function flagCreator(creator, tokenAddress, tokenSymbol, tokenName, clientFingerprint, userId, uniqueUserId) {
    const creatorAddress = normalizeCreatorAddress(creator);
    if (!creatorAddress) {
        return { success: false, message: 'Invalid creator address' };
    }
    console.log("PRC: Flagging creator (global):", creatorAddress, "for token:", tokenAddress);
    const identity = await getIdentityPayload(clientFingerprint, {
        includeIP: true,
        preferredInstallId: userId,
        preferredUniqueUserId: uniqueUserId
    });
    for (let attempt = 1; attempt <= 2; attempt++) {
        try {
            const resp = await fetchWithTimeout(`${API_BASE}/flags/${creatorAddress}`, {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({
                    tokenAddress,
                    tokenSymbol: tokenSymbol || null,
                    tokenName: tokenName || null,
                    userIP: identity.userIP || null,
                    installId: identity.installId || null,
                    uniqueUserId: identity.uniqueUserId || null,
                    fingerprint: identity.fingerprint || null
                }),
                timeout: 6000
            });
            let data = {};
            try {
                data = await resp.json();
            } catch (_) {
                // Ignore parse error, use empty object
            }

            if (resp.ok) {
                invalidateFlagCacheForCreator(creatorAddress);
                void setIsCreatorFlaggedLocally(creatorAddress); // Fire and forget for speed
                const cooldownUntil = Number(data.cooldownUntil || data.userCooldownUntil || 0) || 0;
                return {
                    success: true,
                    count: data.count || 0,
                    cooldownUntil,
                    ruggerThreshold: parseRuggerThreshold(data, 5),
                    survivorMinMarketCap: Math.max(1000, parseInt(data.survivorMinMarketCap, 10) || 70000)
                };
            }
            if (resp.status === 429) {
                return {
                    success: false,
                    message: 'Rate limited',
                    cooldownUntil: Number(data.cooldownUntil || data.userCooldownUntil || 0) || 0
                };
            }
            return { success: false, message: data?.message || 'Backend rejected flag' };
        } catch (err) {
            if (attempt === 2) {
                console.warn("PRC: Backend flag registration failed:", err?.message || err);
                return { success: false, message: 'Backend unavailable. Flag was not registered.' };
            }
        }
    }
    return { success: false, message: 'Backend unavailable. Flag was not registered.' };
}

async function submitAppeal(creator, wallet, description) {
    console.log("PRC: Submitting appeal for:", creator);
    try {
        const resp = await fetch(`${API_BASE}/appeals`, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ creatorAddress: creator, walletAddress: wallet, description, userIP: await getUserIP() })
        });
        return await resp.json();
    } catch (err) {
        console.error("PRC: Appeal failed:", err);
        return { success: false, message: "Network error" };
    }
}

async function getFlagCount(creator, clientFingerprint, userId, uniqueUserId) {
    try {
        const creatorAddress = normalizeCreatorAddress(creator);
        if (!creatorAddress) {
            return { count: 0, cooldownUntil: 0, appVersion: "Alpha Testing", ruggerThreshold: 5, survivorMinMarketCap: 70000 };
        }
        const identity = await getIdentityPayload(clientFingerprint, {
            includeIP: false,
            preferredInstallId: userId,
            preferredUniqueUserId: uniqueUserId
        });
        const fpKey = identity.fingerprint ? JSON.stringify(identity.fingerprint) : 'no-fp';
        const cacheKey = `${creatorAddress}|${identity.uniqueUserId || identity.installId || ''}|${fpKey}`;
        const now = Date.now();
        const cached = flagCountCache.get(cacheKey);
        if (cached && (now - cached.at) < FLAG_CACHE_TTL_MS) {
            return cached.value;
        }
        if (flagCountInFlight.has(cacheKey)) {
            return await flagCountInFlight.get(cacheKey);
        }

        const task = (async () => {
            const params = new URLSearchParams({
                installId: identity.installId || ''
            });
            if (identity.uniqueUserId) {
                params.set('uniqueUserId', identity.uniqueUserId);
            }
            if (identity.fingerprint) {
                params.set('fingerprint', JSON.stringify(identity.fingerprint));
            }
            const qs = params.toString();
            const [resp, isLocallyFlagged] = await Promise.all([
                fetchWithTimeout(`${API_BASE}/flags/${creatorAddress}?${qs}`, { timeout: 6000 }).catch(err => {
                    console.warn("PRC: Flag count fetch failed:", err);
                    return { ok: false };
                }),
                getIsCreatorFlaggedLocally(creatorAddress)
            ]);

            if (resp && resp.ok) {
                const data = await resp.json().catch(() => ({}));
                const value = {
                    count: data.count || 0,
                    cooldownUntil: data.userCooldownUntil || 0,
                    userFlagged: isLocallyFlagged || !!(data.userFlagged || data.user_flagged || data.voted || data.userVoted || (data.userCooldownUntil > 0)),
                    appVersion: data.appVersion || "Alpha Testing",
                    ruggerThreshold: parseRuggerThreshold(data, 5),
                    survivorMinMarketCap: Math.max(1000, parseInt(data.survivorMinMarketCap, 10) || 70000)
                };
                flagCountCache.set(cacheKey, { value, at: Date.now() });
                return value;
            }
            return { count: 0, cooldownUntil: 0, userFlagged: isLocallyFlagged, appVersion: "Alpha Testing", ruggerThreshold: 5, survivorMinMarketCap: 70000 };
        })();

        flagCountInFlight.set(cacheKey, task);
        try {
            return await task;
        } finally {
            flagCountInFlight.delete(cacheKey);
        }
    } catch (err) {
        console.warn("PRC: Backend failed for getFlagCount:", err);
    }
    const finalIsLocallyFlagged = await getIsCreatorFlaggedLocally(creator);
    return { count: 0, cooldownUntil: 0, userFlagged: finalIsLocallyFlagged, appVersion: "Alpha Testing", ruggerThreshold: 5, survivorMinMarketCap: 70000 };
}

async function syncCloudStats(clientFingerprint, userId, uniqueUserId, statsPayload, statsUpdatedAt) {
    try {
        const identity = await getIdentityPayload(clientFingerprint, {
            includeIP: false,
            preferredInstallId: userId,
            preferredUniqueUserId: uniqueUserId
        });
        const safeUpdatedAt = Math.max(0, parseInt(statsUpdatedAt, 10) || 0);
        const hasPayload = statsPayload && typeof statsPayload === 'object' && !Array.isArray(statsPayload);
        const body = {
            installId: identity.installId || null,
            uniqueUserId: identity.uniqueUserId || null,
            fingerprint: identity.fingerprint || null,
            statsUpdatedAt: safeUpdatedAt
        };
        if (hasPayload) {
            body.statsPayload = statsPayload;
        }
        const resp = await fetchWithTimeout(`${API_BASE}/users/profile/sync`, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify(body),
            timeout: 7000
        });
        const data = await resp.json().catch(() => ({}));
        if (!resp.ok) {
            return {
                success: false,
                message: data?.message || 'Profile sync failed',
                uniqueUserId: identity.uniqueUserId || identity.installId || null
            };
        }
        return {
            success: true,
            uniqueUserId: String(data?.uniqueUserId || identity.uniqueUserId || identity.installId || '').slice(0, 64) || null,
            installId: data?.installId || identity.installId || null,
            recoveryCode: data?.recoveryCode || null,
            statsPayload: (data?.statsPayload && typeof data.statsPayload === 'object') ? data.statsPayload : null,
            statsVersion: Math.max(0, Number(data?.statsVersion) || 0),
            statsUpdatedAt: Math.max(0, Number(data?.statsUpdatedAt) || 0),
            decision: data?.decision || 'up_to_date'
        };
    } catch (err) {
        console.warn("PRC: syncCloudStats failed:", err?.message || err);
        return { success: false, message: 'Profile sync failed' };
    }
}

async function restoreCloudStats(clientFingerprint, userId, recoveryCode) {
    try {
        const normalizedCode = String(recoveryCode || '').trim();
        if (!normalizedCode) {
            return { success: false, message: 'Recovery code is required' };
        }
        const identity = await getIdentityPayload(clientFingerprint, {
            includeIP: false,
            preferredInstallId: userId
        });
        const resp = await fetchWithTimeout(`${API_BASE}/users/profile/restore`, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({
                recoveryCode: normalizedCode,
                installId: identity.installId || null,
                fingerprint: identity.fingerprint || null
            }),
            timeout: 7000
        });
        const data = await resp.json().catch(() => ({}));
        if (!resp.ok) {
            return {
                success: false,
                message: data?.message || 'Could not restore profile'
            };
        }
        return {
            success: true,
            uniqueUserId: String(data?.uniqueUserId || '').slice(0, 64) || null,
            installId: data?.installId || identity.installId || null,
            recoveryCode: data?.recoveryCode || normalizedCode,
            statsPayload: (data?.statsPayload && typeof data.statsPayload === 'object') ? data.statsPayload : null,
            statsVersion: Math.max(0, Number(data?.statsVersion) || 0),
            statsUpdatedAt: Math.max(0, Number(data?.statsUpdatedAt) || 0)
        };
    } catch (err) {
        console.warn("PRC: restoreCloudStats failed:", err?.message || err);
        return { success: false, message: 'Could not restore profile' };
    }
}

async function getUserStats(clientFingerprint, userId, uniqueUserId) {
    try {
        const identity = await getIdentityPayload(clientFingerprint, {
            includeIP: false,
            preferredInstallId: userId,
            preferredUniqueUserId: uniqueUserId
        });
        const params = new URLSearchParams({
            installId: identity.installId || ''
        });
        if (identity.uniqueUserId) {
            params.set('uniqueUserId', identity.uniqueUserId);
        }
        if (identity.fingerprint) {
            params.set('fingerprint', JSON.stringify(identity.fingerprint));
        }
        const resp = await fetchWithTimeout(`${API_BASE}/users/stats?${params.toString()}`, { timeout: 6000 });
        if (!resp.ok) {
            return {
                success: false,
                flagsCount: 0,
                huntedRuggers: 0,
                score: 0,
                scorePerFlag: 10,
                scorePerHuntedRugger: 100,
                scorePerHatClick: 5,
                scorePerSealProposal: 10,
                scorePerSealGrant: 100,
                flexLevels: null,
                ruggerThreshold: 5
            };
        }
        const data = await resp.json();
        return {
            success: true,
            installId: identity.installId,
            uniqueUserId: identity.uniqueUserId || null,
            flagsCount: Number(data.flagsCount) || 0,
            huntedRuggers: Number(data.huntedRuggers) || 0,
            score: Number(data.score) || 0,
            scorePerFlag: Number(data.scorePerFlag) || 10,
            scorePerHuntedRugger: Number(data.scorePerHuntedRugger) || 100,
            scorePerHatClick: Number(data.scorePerHatClick) || 5,
            scorePerSealProposal: Number(data.scorePerSealProposal) || 10,
            scorePerSealGrant: Number(data.scorePerSealGrant) || 100,
            badgeConfig: Array.isArray(data.badgeConfig) ? data.badgeConfig : null,
            flexLevels: Array.isArray(data.flexLevels) ? data.flexLevels : null,
            ruggerThreshold: parseRuggerThreshold(data, 5)
        };
    } catch (err) {
        console.warn("PRC: Backend failed for getUserStats:", err);
        return {
            success: false,
            flagsCount: 0,
            huntedRuggers: 0,
            score: 0,
            scorePerFlag: 10,
            scorePerHuntedRugger: 100,
            scorePerHatClick: 5,
            scorePerSealProposal: 10,
            scorePerSealGrant: 100,
            flexLevels: null,
            ruggerThreshold: 5
        };
    }
}

async function getSealState(mintAddress, creator, tokenSymbol, tokenAgeDays, clientFingerprint, userId) {
    try {
        const tokenAddress = normalizeCreatorAddress(mintAddress);
        if (!tokenAddress) {
            return { success: false, votes: 0, isOnSeal: false, canVote: false, message: "Invalid token address" };
        }

        const creatorAddress = normalizeCreatorAddress(creator);
        const identity = await getIdentityPayload(clientFingerprint, { includeIP: false, preferredInstallId: userId });
        const params = new URLSearchParams({
            installId: identity.installId || ''
        });
        if (identity.fingerprint) {
            params.set('fingerprint', JSON.stringify(identity.fingerprint));
        }
        if (creatorAddress) params.set('creatorAddress', creatorAddress);
        if (tokenSymbol) params.set('tokenSymbol', String(tokenSymbol).slice(0, 32));
        if (Number.isFinite(Number(tokenAgeDays))) params.set('tokenAgeDays', String(Math.max(0, Number(tokenAgeDays))));

        const resp = await fetchWithTimeout(`${API_BASE}/seal/status/${tokenAddress}?${params.toString()}`, { timeout: 6000 });
        if (!resp.ok) {
            return { success: false, votes: 0, isOnSeal: false, canVote: false, message: "Seal status unavailable" };
        }

        const data = await resp.json();
        const votes = Number(data?.votes ?? data?.seal_of_hermeto ?? data?.count) || 0;
        const isOnSeal = parseBooleanFlag(data?.isOnSeal ?? data?.is_on_seal ?? data?.onSeal ?? data?.on_seal, false);
        const canVote = data?.canVote === undefined ? !isOnSeal : parseBooleanFlag(data.canVote, !isOnSeal);
        return {
            success: true,
            votes,
            isOnSeal,
            canVote,
            message: data?.message || null
        };
    } catch (err) {
        console.warn("PRC: getSealState failed:", err?.message || err);
        return { success: false, votes: 0, isOnSeal: false, canVote: false, message: "Seal status unavailable" };
    }
}

async function voteSealOfHermeto(mintAddress, creator, tokenSymbol, clientFingerprint, userId) {
    try {
        const tokenAddress = normalizeCreatorAddress(mintAddress);
        if (!tokenAddress) {
            return { success: false, votes: 0, isOnSeal: false, canVote: false, message: "Invalid token address" };
        }

        const creatorAddress = normalizeCreatorAddress(creator);
        const identity = await getIdentityPayload(clientFingerprint, { includeIP: true, preferredInstallId: userId });
        const resp = await fetchWithTimeout(`${API_BASE}/seal/vote`, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({
                tokenAddress,
                tokenSymbol: tokenSymbol || null,
                creatorAddress: creatorAddress || null,
                userIP: identity.userIP || null,
                installId: identity.installId || null,
                fingerprint: identity.fingerprint || null
            }),
            timeout: 6000
        });

        const data = await resp.json().catch(() => ({}));
        const votes = Number(data?.votes ?? data?.seal_of_hermeto ?? data?.count) || 0;
        const isOnSeal = Boolean(data?.isOnSeal ?? data?.is_on_seal);
        const canVote = data?.canVote === undefined ? !isOnSeal : Boolean(data.canVote);
        if (resp.ok) {
            return {
                success: true,
                votes,
                isOnSeal,
                canVote,
                message: data?.message || "Vote recorded"
            };
        }
        return {
            success: false,
            votes,
            isOnSeal,
            canVote,
            message: data?.message || "Vote rejected"
        };
    } catch (err) {
        console.warn("PRC: voteSealOfHermeto failed:", err?.message || err);
        return { success: false, votes: 0, isOnSeal: false, canVote: true, message: "Network error" };
    }
}

async function resolveToMint(address) {
    if (!address) return address;
    address = address.trim();
    try {
        // 1. Try direct pair lookup (more reliable for specific addresses)
        const pairResp = await fetchWithTimeout(`https://api.dexscreener.com/latest/dex/pairs/solana/${address}`, { timeout: 5000 });
        if (pairResp.ok) {
            const data = await pairResp.json();
            const resolvedPair = data?.pair || data?.pairs?.[0] || null;
            if (resolvedPair?.baseToken?.address) {
                console.log("PRC: Resolved via direct pair lookup:", resolvedPair.baseToken.address);
                return resolvedPair.baseToken.address;
            }
        }

        // 1b. Try token endpoint (when URL already points to a token mint or alt pair format)
        const tokenResp = await fetchWithTimeout(`https://api.dexscreener.com/latest/dex/tokens/${address}`, { timeout: 5000 });
        if (tokenResp.ok) {
            const tokenData = await tokenResp.json();
            const pairs = Array.isArray(tokenData?.pairs) ? tokenData.pairs : [];
            const exactBase = pairs.find((p) => p?.baseToken?.address && String(p.baseToken.address).toLowerCase() === address.toLowerCase());
            if (exactBase?.baseToken?.address) {
                return exactBase.baseToken.address;
            }
            const firstPair = pairs[0] || null;
            const baseAddress = firstPair?.baseToken?.address;
            const quoteAddress = firstPair?.quoteToken?.address;
            if (baseAddress && /^[1-9A-HJ-NP-Za-km-z]{32,44}$/.test(baseAddress)) {
                if (String(address).toLowerCase() === String(quoteAddress || '').toLowerCase()) {
                    return baseAddress;
                }
                return baseAddress;
            }
        }

        // 2. Fallback to search query
        const searchResp = await fetchWithTimeout(`https://api.dexscreener.com/latest/dex/search?q=${address}`, { timeout: 5000 });
        if (searchResp.ok) {
            const data = await searchResp.json();
            if (data && data.pairs && data.pairs.length > 0) {
                const pairMatch = data.pairs.find(p => p.pairAddress.toLowerCase() === address.toLowerCase());
                if (pairMatch && pairMatch.baseToken) {
                    return pairMatch.baseToken.address;
                }
                const firstPair = data.pairs[0];
                if (firstPair?.baseToken?.address && /^[1-9A-HJ-NP-Za-km-z]{32,44}$/.test(firstPair.baseToken.address)) {
                    return firstPair.baseToken.address;
                }
            }
        }
    } catch (err) {
        console.warn("PRC: resolveToMint error:", err);
    }
    return address;
}

async function analyzeToken(mintAddress, padreDA, devStats, padreDevMintedCount, padreDevSoldStrict, padreDevHoldingPct, clientFingerprint, userId, uniqueUserId) {
    if (!mintAddress) return { success: false, error: "No address provided" };
    mintAddress = mintAddress.trim();
    console.log("PRC: Analyzing token:", mintAddress);

    // Resolve pair-like / lowercased DexScreener ids to canonical token mint first.
    mintAddress = await resolveToMint(mintAddress);
    if (!/^[1-9A-HJ-NP-Za-km-z]{32,44}$/.test(mintAddress)) {
        return { success: false, error: "Invalid address format" };
    }

    let rugCheck = null;
    let dexProfile = null;
    let dexPair = null;
    const ensureRugCheckShape = (data) => {
        const obj = (data && typeof data === 'object') ? data : {};
        const asObjectArray = (value) => Array.isArray(value)
            ? value.filter((item) => item && typeof item === 'object')
            : [];
        const asObjectMap = (value) => (value && typeof value === 'object' && !Array.isArray(value)) ? value : {};
        return {
            ...obj,
            mint: obj.mint || mintAddress,
            score: Number(obj.score) || 0,
            risks: asObjectArray(obj.risks),
            tokenMeta: (obj.tokenMeta && typeof obj.tokenMeta === 'object') ? obj.tokenMeta : {},
            token: (obj.token && typeof obj.token === 'object') ? obj.token : {},
            topHolders: asObjectArray(obj.topHolders),
            markets: asObjectArray(obj.markets),
            knownAccounts: asObjectMap(obj.knownAccounts)
        };
    };

    try {
        const dexPromise = fetchWithTimeout(`https://api.dexscreener.com/latest/dex/tokens/${mintAddress}`, { timeout: 7000 })
            .then(async (dexResp) => {
                if (!dexResp.ok) return null;
                const dexData = await dexResp.json();
                const pairs = Array.isArray(dexData?.pairs) ? dexData.pairs : [];
                const matchedPair = pairs.find((p) => String(p?.baseToken?.address || '').toLowerCase() === mintAddress.toLowerCase()) || pairs[0] || null;
                return {
                    dexProfile: pairs.find(p => p.info)?.info || null,
                    dexPair: matchedPair
                };
            })
            .catch(() => null);

        const summaryUrl = `https://api.rugcheck.xyz/v1/tokens/${mintAddress}/report/summary`;
        const summaryResp = await fetchWithTimeout(summaryUrl, { timeout: 12000 });

        if (summaryResp.ok) {
            const summary = await summaryResp.json();
            // Keep summary as a hard fallback in case full report request fails or times out.
            rugCheck = ensureRugCheckShape(summary);
            const fullUrl = `https://api.rugcheck.xyz/v1/tokens/${mintAddress}/report`;
            try {
                const fullResp = await fetchWithTimeout(fullUrl, { timeout: 16000 });
                if (fullResp.ok) {
                    rugCheck = ensureRugCheckShape(await fullResp.json());
                }
            } catch (fullErr) {
                console.warn("PRC: Full RugCheck report timed out, keeping summary fallback:", fullErr?.message || fullErr);
            }
        } else {
            // Fallback for brand new tokens where summary might fail but full report exists
            const fallbackUrl = `https://api.rugcheck.xyz/v1/tokens/${mintAddress}/report`;
            const fallbackResp = await fetchWithTimeout(fallbackUrl, { timeout: 16000 });
            if (fallbackResp.ok) {
                rugCheck = ensureRugCheckShape(await fallbackResp.json());
            } else {
                console.warn(`PRC: RugCheck fail (${summaryResp.status}), continuing with partial data...`);
                rugCheck = ensureRugCheckShape({
                    mint: mintAddress,
                    score: 0,
                    risks: [],
                    tokenMeta: {},
                    token: { mintAuthority: false, freezeAuthority: false }
                });
            }
        }

        const dexData = await dexPromise;
        if (dexData) {
            dexProfile = dexData.dexProfile;
            dexPair = dexData.dexPair;
        }

    } catch (error) {
        const isAbort = error?.name === 'AbortError' || String(error?.message || '').toLowerCase().includes('aborted');
        const errorMsg = isAbort ? 'Request timed out' : (error.message || error.name || 'Unknown error');
        if (!isAbort) {
            console.warn("PRC: Data fetch warning:", error.name, error.message);
        }
        if (!rugCheck && !dexPair) {
            // Degrade gracefully instead of returning a fatal error to content script.
            console.warn("PRC: Falling back to partial analysis payload due upstream network failure:", errorMsg);
            rugCheck = ensureRugCheckShape({
                mint: mintAddress,
                score: 0,
                creator: normalizeCreatorAddress(padreDA) || "Unknown",
                risks: [],
                tokenMeta: {},
                token: { mintAuthority: false, freezeAuthority: false }
            });
        }
    }

    try {
        let creator = "Unknown";
        let creatorSource = "unknown";

        const tokenName = rugCheck.fileMeta?.name || rugCheck.tokenMeta?.name || dexPair?.baseToken?.name || "Unknown";
        const tokenSymbol = rugCheck.fileMeta?.symbol || rugCheck.tokenMeta?.symbol || dexPair?.baseToken?.symbol || "?";
        const launchPlatform = rugCheck.launchpad?.name || rugCheck.deployPlatform || (dexPair?.dexId ? dexPair.dexId.charAt(0).toUpperCase() + dexPair.dexId.slice(1) : "Unknown");

        const normalizeCreatorCandidate = (value) => {
            const n = normalizeCreatorAddress(value);
            if (!n) return null;
            if (String(n).toLowerCase() === String(mintAddress).toLowerCase()) return null;
            return n;
        };
        const creatorCandidates = [];
        const seenCreatorCandidates = new Set();
        const addCreatorCandidate = (value, source) => {
            const address = normalizeCreatorCandidate(value);
            if (!address) return;
            if (seenCreatorCandidates.has(address)) return;
            seenCreatorCandidates.add(address);
            creatorCandidates.push({ address, source });
        };

        addCreatorCandidate(padreDA, "padre");
        addCreatorCandidate(rugCheck.creator, "rugcheck_creator");
        addCreatorCandidate(rugCheck.tokenMeta?.creator, "tokenmeta_creator");
        if (Array.isArray(rugCheck.tokenMeta?.creators)) {
            const sortedCreators = [...rugCheck.tokenMeta.creators]
                .sort((a, b) => (Number(b?.share) || 0) - (Number(a?.share) || 0))
                .slice(0, 3);
            for (const c of sortedCreators) addCreatorCandidate(c?.address, "tokenmeta_creators");
        }
        if (Array.isArray(rugCheck.topHolders) && rugCheck.topHolders.length > 0) {
            const firstHolder = rugCheck.topHolders[0];
            if (Number(firstHolder?.pct) > 50 && firstHolder?.owner !== '5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1') {
                addCreatorCandidate(firstHolder.owner, "top_holder");
            }
        }

        let mintInitCreatorHint = null;
        const hasStrongCreatorCandidate = creatorCandidates.some(c => ['padre', 'rugcheck_creator', 'tokenmeta_creator', 'tokenmeta_creators'].includes(c.source));
        if (!hasStrongCreatorCandidate || creatorCandidates.length === 0) {
            mintInitCreatorHint = await Promise.race([
                getCreatorFromMintInitOnChain(mintAddress),
                new Promise(resolve => setTimeout(() => resolve(null), 4200))
            ]);
            if (mintInitCreatorHint?.creator) addCreatorCandidate(mintInitCreatorHint.creator, "mint_init_signer");
        }

        const EMPTY_FLOW = { hasSell: false, hasData: false, incoming: 0, outgoing: 0, netOutflow: 0, flowRatio: 0, examinedTx: 0, relevantTx: 0 };
        let onChainBalanceResult = null;
        let onChainFlowResult = EMPTY_FLOW;
        if (creatorCandidates.length > 0) {
            const sourcePriority = { padre: 1, rugcheck_creator: 2, tokenmeta_creator: 3, tokenmeta_creators: 4, mint_init_signer: 5, top_holder: 9 };
            const probeCandidates = [...creatorCandidates].sort((a, b) => (sourcePriority[a.source] || 99) - (sourcePriority[b.source] || 99)).slice(0, 3);
            let bestProbe = null;
            for (const candidate of probeCandidates) {
                const probeResult = await Promise.race([
                    Promise.all([getDevHoldingsOnChain(candidate.address, mintAddress), getRecentDevSellSignalOnChain(candidate.address, mintAddress)]),
                    new Promise(resolve => setTimeout(() => resolve([null, EMPTY_FLOW]), 2600))
                ]);
                const [balance, flowRaw] = Array.isArray(probeResult) ? probeResult : [null, EMPTY_FLOW];
                const flow = flowRaw || EMPTY_FLOW;
                const outgoing = Number(flow.outgoing) || 0;
                const incoming = Number(flow.incoming) || 0;
                const hasData = !!flow.hasData || (Number(flow.relevantTx) || 0) > 0 || (Number(flow.examinedTx) || 0) > 0;
                const balanceKnown = (balance !== null && balance !== undefined && Number.isFinite(Number(balance)));
                const nearZeroBalance = balanceKnown && Number(balance) <= 0.000001;
                let score = 0;
                if (candidate.source === "padre") score += 6;
                if (candidate.source === "rugcheck_creator" || candidate.source === "tokenmeta_creator") score += 8;
                if (candidate.source === "mint_init_signer") score += 14;
                if (candidate.source === "top_holder") score -= 6;
                if (hasData) score += 20;
                if (outgoing > 0.0001) score += 24;
                if (flow.hasSell) score += 40;
                if (balanceKnown) score += 6;
                if (nearZeroBalance && (flow.hasSell || outgoing > 0.0001 || incoming > 0.0001)) score += 18;
                if (!hasData && !flow.hasSell && !balanceKnown) score -= 8;

                if (!bestProbe || score > bestProbe.score) bestProbe = { address: candidate.address, source: candidate.source, balance, flow, score };
                if (score >= 70 || (candidate.source === "padre" && (hasData || balanceKnown))) break;
            }
            if (bestProbe) {
                creator = bestProbe.address;
                creatorSource = bestProbe.source;
                onChainBalanceResult = bestProbe.balance;
                onChainFlowResult = bestProbe.flow || EMPTY_FLOW;
            }
        }
        if ((!creator || creator === "Unknown") && mintInitCreatorHint?.creator) {
            creator = mintInitCreatorHint.creator;
            creatorSource = "mint_init_signer";
        }

        const flagData = await getFlagCount(creator, clientFingerprint, userId, uniqueUserId);
        let resolvedDevMintedCount = Number.isFinite(Number(padreDevMintedCount)) ? Number(padreDevMintedCount) : null;
        if (resolvedDevMintedCount !== null && creator !== "Unknown") await setCreatorMintedCountInStore(creator, resolvedDevMintedCount);
        if (resolvedDevMintedCount === null && creator !== "Unknown") {
            resolvedDevMintedCount = await Promise.race([getCreatorMintedTokenCountOnChain(creator), new Promise(resolve => setTimeout(() => resolve(null), 5500))]);
            if (Number.isFinite(Number(resolvedDevMintedCount)) && Number(resolvedDevMintedCount) > 0) await setCreatorMintedCountInStore(creator, resolvedDevMintedCount);
            else {
                const storedCount = await getCreatorMintedCountFromStore(creator);
                if (Number.isFinite(Number(storedCount)) && Number(storedCount) > 0) resolvedDevMintedCount = Number(storedCount);
            }
        }

        const ruggerThreshold = parseInt(flagData.ruggerThreshold, 10) || 5;
        const flagCount = flagData.count || 0;
        const survivorMinMarketCap = Math.max(1000, parseInt(flagData.survivorMinMarketCap, 10) || 70000);
        const cooldownUntil = flagData.cooldownUntil || 0;

        const topHolders = (rugCheck.topHolders || []).filter(h => h && typeof h === 'object').map(h => ({
            owner: h.owner, pct: h.pct, amount: h.uiAmountString,
            isKnown: !!rugCheck.knownAccounts?.[h.owner],
            knownName: rugCheck.knownAccounts?.[h.owner]?.name || ''
        }));

        const lpLockedPct = rugCheck.lpLockedPct || (rugCheck.markets?.[0]?.lp?.lpLockedPct || 0);
        let devPct = 0;
        let devAmount = "0";
        if (creator !== "Unknown") {
            const h = topHolders.find(h => h.owner === creator);
            if (h) { devPct = Number(h.pct) || 0; devAmount = h.amount; }
        }
        if (Number.isFinite(Number(padreDevHoldingPct)) && Number(padreDevHoldingPct) >= 0) {
            if (!Number.isFinite(devPct) || devPct <= 0.0001 || Math.abs(devPct - Number(padreDevHoldingPct)) >= 0.20) devPct = Number(padreDevHoldingPct);
        }

        let safetyInsights = [];
        let penalty = 0;
        const rugCheckScore = rugCheck.score || 0;
        let forceRugged = false;

        const soldKeywords = ['sold', 'sell', 'dump'];
        const actorKeywords = ['creator', 'dev', 'deployer', 'insider', 'team'];
        const soldRisk = (rugCheck.risks || []).find(r => {
            const text = `${String(r?.name || '').toLowerCase()} ${String(r?.description || '').toLowerCase()}`;
            return soldKeywords.some(k => text.includes(k)) && actorKeywords.some(k => text.includes(k));
        });

        let onChainBalance = onChainBalanceResult;
        const onChainFlowSold = !!onChainFlowResult?.hasSell;
        const onChainFlowOutgoing = Number(onChainFlowResult?.outgoing) || 0;
        const onChainFlowIncoming = Number(onChainFlowResult?.incoming) || 0;
        const onChainFlowNetOut = Number(onChainFlowResult?.netOutflow) || (onChainFlowOutgoing - onChainFlowIncoming);
        const onChainFlowRatio = Number(onChainFlowResult?.flowRatio) || (onChainFlowIncoming > 0 ? (onChainFlowOutgoing / onChainFlowIncoming) : 0);
        const devPctNum = Number(devPct) || 0;
        const devAmountNum = parseNumericLoose(devAmount);
        const creatorBalanceNumRaw = Number(rugCheck.creatorBalance);
        const creatorBalanceKnown = Number.isFinite(creatorBalanceNumRaw);
        const hasVisibleDevHoldings = devPctNum > 0.0001 || devAmountNum > 0.000001;
        const creatorBalanceIsZeroishGlobal = creatorBalanceKnown && creatorBalanceNumRaw <= 0.000001 && !hasVisibleDevHoldings;
        const strictSoldAmount = (padreDevSoldStrict && typeof padreDevSoldStrict === 'object' && padreDevSoldStrict.found === true) ? (Number(padreDevSoldStrict?.sold) || 0) : 0;
        const strictSoldSaysSold = strictSoldAmount > 0.000001;
        const strictSoldSaysNotSold = (padreDevSoldStrict && typeof padreDevSoldStrict === 'object' && padreDevSoldStrict.found === true) && strictSoldAmount <= 0.000001;
        let scrapedSellSignal = !!(devStats && (devStats.hasSold || (Number(devStats.sold) || 0) > 0));
        const devStatsBought = Number(devStats?.bought) || 0;
        let devStatsSold = Number(devStats?.sold) || 0;
        const meaningfulScrapedSold = devStatsBought > 0 && devStatsSold > 15 && (devStatsSold > devStatsBought || devStatsSold >= (devStatsBought * 0.20));
        const explicitStrictSoldSignal = strictSoldSaysSold && strictSoldAmount > 15;
        const lowHoldingNow = devPctNum <= 1.0;
        const onChainPrimarySoldSignal = creator !== "Unknown" && ((onChainFlowSold && (onChainBalance <= 0.000001 || devPctNum <= 0.10 || (lowHoldingNow && onChainFlowNetOut > 0.001 && onChainFlowRatio >= 0.65))) || (onChainFlowOutgoing > 0.002 && onChainFlowNetOut > 0.001 && onChainFlowRatio >= 0.85 && (onChainBalance <= 0.000001 || devPctNum <= 0.10)));

        const hasOnChainEvidence = (onChainBalanceResult !== null && Number.isFinite(Number(onChainBalanceResult))) || onChainFlowResult?.hasData || (Number(onChainFlowResult?.examinedTx) || 0) > 0;
        const strictNoSellReliable = !hasOnChainEvidence && strictSoldSaysNotSold && !meaningfulScrapedSold;
        const suppressSellHeuristics = !hasOnChainEvidence && (strictNoSellReliable || (devStats && (Number(devStats.sold) || 0) <= 0.000001 && (Number(devStats.bought) || 0) > 0 && devPctNum > 0.5 && !meaningfulScrapedSold));

        let identifiedDump = false;
        // Path 1: Original Padre scraping gate
        if (!suppressSellHeuristics && devStats?.isDump && (onChainPrimarySoldSignal || explicitStrictSoldSignal || (devStatsBought > 0 && devStatsSold > 30 && (devStatsSold > devStatsBought || (lowHoldingNow && devStatsSold >= (devStatsBought * 0.80)))) || creatorBalanceIsZeroishGlobal || (onChainFlowSold && (onChainFlowNetOut > 0.001 || onChainFlowRatio >= 0.65)))) identifiedDump = true;

        // Path 2: On-chain primary sold signal alone (strong evidence, no scraping needed)
        if (!identifiedDump && !suppressSellHeuristics && onChainPrimarySoldSignal && lowHoldingNow) {
            identifiedDump = true;
        }

        // Path 3: RugCheck soldRisk + creator balance is zero (API-based, no scraping needed)
        if (!identifiedDump && !suppressSellHeuristics && soldRisk && (creatorBalanceIsZeroishGlobal || (lowHoldingNow && devPctNum <= 0.10))) {
            identifiedDump = true;
        }

        // Path 4: On-chain flow sold + significant outflow + low holding (no scraping needed)
        if (!identifiedDump && !suppressSellHeuristics && onChainFlowSold && lowHoldingNow && onChainFlowNetOut > 0.001 && onChainFlowRatio >= 0.65) {
            identifiedDump = true;
        }

        const meaningfullyMoreSold = devStatsSold > (devStatsBought * 1.02) && (devStatsSold - devStatsBought) > 5;
        const isFullExit = scrapedSellSignal && devPctNum <= 0.1 && devStatsSold > 15;

        if (identifiedDump) { penalty += 100; safetyInsights.push(`🚨 CRITICAL: Developer DUMP detected`); forceRugged = true; }
        else if (scrapedSellSignal && lowHoldingNow) {
            if (meaningfullyMoreSold || isFullExit) { 
                penalty += 90; 
                safetyInsights.push(isFullExit ? `🚨 CRITICAL: Developer FULL EXIT detected (Dumped position)` : `🚨 CRITICAL: Developer sold MORE than bought`); 
                forceRugged = true; 
                identifiedDump = true; 
            }
            else { penalty += 20; safetyInsights.push(`⚠️ WARNING: Developer position reduced`); }
        }

        if (onChainPrimarySoldSignal) safetyInsights.push("WARNING: On-chain evidence shows deployer outflow.");
        if (onChainFlowSold && !suppressSellHeuristics && (lowHoldingNow || creatorBalanceIsZeroishGlobal || identifiedDump || soldRisk)) { penalty += 45; safetyInsights.push("WARNING: Recent developer outflow."); }

        const tokenAgeDays = dexPair ? (Date.now() - (dexPair.pairCreatedAt || Date.now())) / (1000 * 60 * 60 * 24) : 0;
        const isVeryNewToken = tokenAgeDays > 0 && tokenAgeDays < 7;
        if (isVeryNewToken) { penalty += 25; safetyInsights.push("⚠️ WARNING: Token age is under 7 days."); }
        if (isVeryNewToken && creatorBalanceIsZeroishGlobal && devPctNum <= 0.0001 && !suppressSellHeuristics) { penalty += 35; safetyInsights.push("⚠️ WARNING: Developer likely sold (0% hold on new token)."); }

        let isSurvivor = false, isCTO = false;
        if (dexProfile) {
            const d = (dexProfile.description || "").toUpperCase();
            if (d.includes("CTO") || d.includes("COMMUNITY TAKE OVER")) isCTO = true;
        }
        if (dexPair) {
            const mc = dexPair.marketCap || dexPair.fdv || 0;
            if (tokenAgeDays >= 60 && mc >= survivorMinMarketCap && (dexPair.liquidity?.usd || 0) > 0) {
                isSurvivor = true;
                if (rugCheckScore < 4000) { forceRugged = false; penalty = Math.max(0, penalty - 100); safetyInsights.push(`💎 SURVIVOR: Proved stronger than deployer.`); }
                else { penalty = Math.max(0, penalty - 40); safetyInsights.push(`💎 PROVEN: Proved stronger than deployer.`); }
            }
        }

        if (topHolders.filter(h => !h.isKnown && h.pct > 5).length >= 3) { penalty += 35; safetyInsights.push("Multiple concentrated unknown holders"); }
        if (flagCount > 0) { penalty += Math.min(60, flagCount * 12); safetyInsights.push(`Community flags: ${flagCount}`); }

        const combinedScore = (rugCheckScore / 100) + penalty;
        if (rugCheckScore > 5000 || combinedScore > 75) forceRugged = true;

        let integratedRating = "SAFE";
        if (forceRugged) integratedRating = "DANGER";
        else if (combinedScore > 30 || rugCheckScore > 2000) integratedRating = "WARNING";
        else if (penalty > 15) integratedRating = "SUSPECT";

        // --- RUGGER ENFORCEMENT ---
        const isRugger = flagCount >= ruggerThreshold;
        if (isRugger || rugCheck.rugged) {
            integratedRating = "DANGER";
            if (isRugger && !safetyInsights.some(i => i.includes("Rugger deployer"))) safetyInsights.push("🚨 DANGER: Rugger deployer detected");
        }

        let finalIsCTO = false;
        if (isCTO || isSurvivor) {
            if (isCTO) {
                finalIsCTO = true;
                safetyInsights.unshift("✅ COMMUNITY TAKE OVER (CTO) DETECTED");
                if (identifiedDump || rugCheck.rugged) {
                    integratedRating = "DANGER";
                    safetyInsights.push("⚠️ WARNING: Even in CTO, a significant developer dump was detected.");
                } else {
                    integratedRating = "SAFE";
                }
            } else if (isSurvivor) {
                // Pure survivor (60+ days, good market cap)
                safetyInsights.unshift("✅ SURVIVOR: Proven resilience.");
                if (identifiedDump || rugCheck.rugged) {
                    integratedRating = "DANGER";
                } else {
                    integratedRating = "SAFE";
                }
            }
        }
        if (flagCount > 0 && integratedRating === "SAFE" && !isSurvivor && !finalIsCTO) integratedRating = "WARNING";
        if (isVeryNewToken && integratedRating !== "DANGER" && !isSurvivor && !finalIsCTO) integratedRating = "WARNING";
        if (isRugger || rugCheck.rugged) integratedRating = "DANGER"; // Re-enforce as final priority

        const isRugged = identifiedDump || rugCheck.rugged;

        // Compute devSold from all available sources (not just Padre scraping)
        const devSoldComputed = !!(onChainPrimarySoldSignal || identifiedDump || scrapedSellSignal || explicitStrictSoldSignal || soldRisk || creatorBalanceIsZeroishGlobal);

        return {
            success: true, mint: rugCheck.mint || mintAddress, name: tokenName, symbol: tokenSymbol,
            creator, devPct, devAmount, devMintedCount: Number.isFinite(resolvedDevMintedCount) ? resolvedDevMintedCount : null,
            devLockedPct: 0, burns: Array.isArray(rugCheck.markets) ? [] : [], // Simplified for space
            creatorBalance: rugCheck.creatorBalance || 0, platform: launchPlatform,
            score: rugCheckScore, integratedRating, safetyInsights: [...new Set(safetyInsights)],
            riskLevel: integratedRating.toLowerCase(), rugged: isRugged,
            devSold: devSoldComputed,
            isCTO: finalIsCTO, mintAuthority: !!rugCheck.token?.mintAuthority, freezeAuthority: !!rugCheck.token?.freezeAuthority,
            risks: (rugCheck.risks || []).map(r => ({ name: r.name, level: r.level, description: r.description })),
            totalLiquidity: rugCheck.totalMarketLiquidity || 0, lpLockedPct: Math.round(lpLockedPct * 100) / 100,
            totalHolders: rugCheck.totalHolders || 0, topHolders, flagCount, ruggerThreshold, survivorMinMarketCap, cooldownUntil,
            userFlagged: !!flagData.userFlagged,
            appVersion: flagData.appVersion || "Alpha Testing", headerURL: dexProfile?.header || null, isSurvivor, tokenAgeDays,
            dexPairAvailable: !!dexPair, creatorSource
        };
    } catch (error) {
        console.error("PRC: Final parse error:", error);
        return { success: false, error: "Analysis failed: " + error.message };
    }
}
