// Provide a localStorage mock for Node.js test environment.
// Must be set before requiring the module since it calls loadDeltaFromStorage()
// at module load time.
const localStorageStore = {};
global.localStorage = {
    getItem: (key) =>
        Object.prototype.hasOwnProperty.call(localStorageStore, key)
            ? localStorageStore[key]
            : null,
    setItem: (key, value) => {
        localStorageStore[key] = String(value);
    },
    removeItem: (key) => {
        delete localStorageStore[key];
    },
};

const {
    isPhishingDomain,
    loadConfig,
    getBlocklistSize,
    getDeltaSize,
    hostnameVariants,
    _reset,
    _getVendoredBlacklistSize,
    _getDeltaBlacklist,
} = require("../src/shared/phishingDomains");

// Reset delta state before each test to avoid cross-test contamination.
// Note: vendored sets are immutable and always present.
beforeEach(() => {
    _reset();
    // Clear localStorage mock between tests
    for (const key of Object.keys(localStorageStore)) {
        delete localStorageStore[key];
    }
});

describe("phishingDomains", () => {
    describe("vendored blocklist", () => {
        test("vendored blacklist is loaded from bundled JSON", () => {
            // The vendored blocklist should have a large number of entries
            expect(_getVendoredBlacklistSize()).toBeGreaterThan(100000);
        });

        test("detects domains from vendored blacklist", () => {
            // These are well-known phishing domains in the vendored list
            expect(isPhishingDomain("hopprotocol.pro")).toBe(true);
            expect(isPhishingDomain("blast-pools.pages.dev")).toBe(true);
        });

        test("getBlocklistSize includes vendored entries", () => {
            expect(getBlocklistSize()).toBeGreaterThan(100000);
        });
    });

    describe("hostnameVariants", () => {
        test("returns exact hostname plus parent domains", () => {
            const variants = hostnameVariants("sub.evil.com");
            expect(variants).toEqual(["sub.evil.com", "evil.com"]);
        });

        test("returns just the hostname for a bare domain", () => {
            const variants = hostnameVariants("example.com");
            expect(variants).toEqual(["example.com"]);
        });

        test("handles deep subdomain chains", () => {
            const variants = hostnameVariants("a.b.c.d.com");
            expect(variants).toEqual([
                "a.b.c.d.com",
                "b.c.d.com",
                "c.d.com",
                "d.com",
            ]);
        });

        test("lowercases hostnames", () => {
            const variants = hostnameVariants("Evil.COM");
            expect(variants).toEqual(["evil.com"]);
        });
    });

    describe("delta computation via loadConfig", () => {
        test("loadConfig computes delta of new entries not in vendored list", () => {
            loadConfig({
                blacklist: [
                    "brand-new-scam-site-xyz123.com",
                    "hopprotocol.pro", // already in vendored
                ],
            });
            // Only the new domain should be in the delta
            expect(
                _getDeltaBlacklist().has("brand-new-scam-site-xyz123.com"),
            ).toBe(true);
            expect(_getDeltaBlacklist().has("hopprotocol.pro")).toBe(false);
            expect(getDeltaSize()).toBe(1);
        });

        test("re-loading config replaces previous delta", () => {
            loadConfig({
                blacklist: ["first-scam-xyz.com"],
            });
            expect(isPhishingDomain("first-scam-xyz.com")).toBe(true);

            loadConfig({
                blacklist: ["second-scam-xyz.com"],
            });
            expect(isPhishingDomain("first-scam-xyz.com")).toBe(false);
            expect(isPhishingDomain("second-scam-xyz.com")).toBe(true);
        });

        test("getBlocklistSize includes both vendored and delta", () => {
            const baseSize = getBlocklistSize();
            loadConfig({
                blacklist: ["delta-only-scam-xyz.com"],
            });
            expect(getBlocklistSize()).toBe(baseSize + 1);
        });
    });

    describe("isPhishingDomain with delta + vendored", () => {
        test("detects domain from delta blacklist", () => {
            loadConfig({
                blacklist: ["fresh-scam-xyz.com"],
            });
            expect(isPhishingDomain("fresh-scam-xyz.com")).toBe(true);
        });

        test("detects domain from vendored blacklist", () => {
            // No delta loaded — vendored still works
            expect(isPhishingDomain("hopprotocol.pro")).toBe(true);
        });

        test("returns false for clean domains", () => {
            expect(isPhishingDomain("etherscan.io")).toBe(false);
            expect(isPhishingDomain("example.com")).toBe(false);
        });

        test("detects subdomain of blacklisted domain (vendored)", () => {
            expect(isPhishingDomain("app.hopprotocol.pro")).toBe(true);
        });

        test("detects subdomain of blacklisted domain (delta)", () => {
            loadConfig({
                blacklist: ["delta-phish-xyz.com"],
            });
            expect(isPhishingDomain("sub.delta-phish-xyz.com")).toBe(true);
        });

        test("case-insensitive matching", () => {
            loadConfig({
                blacklist: ["Delta-Scam-XYZ.COM"],
            });
            expect(isPhishingDomain("delta-scam-xyz.com")).toBe(true);
            expect(isPhishingDomain("DELTA-SCAM-XYZ.COM")).toBe(true);
        });

        test("returns false for empty/null hostname", () => {
            expect(isPhishingDomain("")).toBe(false);
            expect(isPhishingDomain(null)).toBe(false);
        });

        test("handles config with no blacklist key", () => {
            loadConfig({});
            expect(getDeltaSize()).toBe(0);
            // Vendored list still works
            expect(isPhishingDomain("hopprotocol.pro")).toBe(true);
        });
    });

    describe("localStorage persistence", () => {
        test("saveDeltaToStorage persists delta under 256KiB", () => {
            loadConfig({
                blacklist: ["persisted-scam-xyz.com"],
            });
            const stored = localStorage.getItem("phishing-delta");
            expect(stored).not.toBeNull();
            const data = JSON.parse(stored);
            expect(data.blacklist).toContain("persisted-scam-xyz.com");
        });

        test("delta is cleared on _reset", () => {
            loadConfig({
                blacklist: ["temp-scam-xyz.com"],
            });
            expect(getDeltaSize()).toBe(1);
            _reset();
            expect(getDeltaSize()).toBe(0);
        });
    });

    describe("real-world blocklist patterns", () => {
        test("detects known phishing domains from vendored list", () => {
            expect(isPhishingDomain("uniswap-trade.web.app")).toBe(true);
            expect(isPhishingDomain("hopprotocol.pro")).toBe(true);
            expect(isPhishingDomain("blast-pools.pages.dev")).toBe(true);
        });

        test("does not flag legitimate domains", () => {
            expect(isPhishingDomain("opensea.io")).toBe(false);
            expect(isPhishingDomain("etherscan.io")).toBe(false);
        });
    });
});
