/**
 * Unit tests for ublock plugin
 *
 * Run with: node --test tests/test_ublock.js
 */

const assert = require('assert');
const fs = require('fs');
const path = require('path');
const { describe, it, before, after, beforeEach, afterEach } = require('node:test');

// Test fixtures
const TEST_DIR = path.join(__dirname, '.test_fixtures');
const TEST_EXTENSIONS_DIR = path.join(TEST_DIR, 'chrome_extensions');

describe('ublock plugin', () => {
    before(() => {
        if (!fs.existsSync(TEST_DIR)) {
            fs.mkdirSync(TEST_DIR, { recursive: true });
        }
    });

    after(() => {
        if (fs.existsSync(TEST_DIR)) {
            fs.rmSync(TEST_DIR, { recursive: true, force: true });
        }
    });

    describe('EXTENSION metadata', () => {
        it('should have correct webstore_id for uBlock Origin', () => {
            const { EXTENSION } = require('../on_Snapshot__03_ublock.js');

            assert.strictEqual(EXTENSION.webstore_id, 'cjpalhdlnbpafiamejdnhcphjbkeiagm');
        });

        it('should have correct name', () => {
            const { EXTENSION } = require('../on_Snapshot__03_ublock.js');

            assert.strictEqual(EXTENSION.name, 'ublock');
        });
    });

    describe('installUblockExtension', () => {
        beforeEach(() => {
            process.env.CHROME_EXTENSIONS_DIR = TEST_EXTENSIONS_DIR;

            if (!fs.existsSync(TEST_EXTENSIONS_DIR)) {
                fs.mkdirSync(TEST_EXTENSIONS_DIR, { recursive: true });
            }
        });

        afterEach(() => {
            if (fs.existsSync(TEST_EXTENSIONS_DIR)) {
                fs.rmSync(TEST_EXTENSIONS_DIR, { recursive: true });
            }

            delete process.env.CHROME_EXTENSIONS_DIR;
        });

        it('should use cached extension if available', async () => {
            const { installUblockExtension } = require('../on_Snapshot__03_ublock.js');

            // Create fake cache
            const cacheFile = path.join(TEST_EXTENSIONS_DIR, 'ublock.extension.json');
            const fakeExtensionDir = path.join(TEST_EXTENSIONS_DIR, 'fake_ublock');

            fs.mkdirSync(fakeExtensionDir, { recursive: true });
            fs.writeFileSync(
                path.join(fakeExtensionDir, 'manifest.json'),
                JSON.stringify({ version: '1.67.0' })
            );

            const fakeCache = {
                webstore_id: 'cjpalhdlnbpafiamejdnhcphjbkeiagm',
                name: 'ublock',
                unpacked_path: fakeExtensionDir,
                version: '1.67.0'
            };

            fs.writeFileSync(cacheFile, JSON.stringify(fakeCache));

            const result = await installUblockExtension();

            assert.notStrictEqual(result, null);
            assert.strictEqual(result.webstore_id, 'cjpalhdlnbpafiamejdnhcphjbkeiagm');
        });

        it('should not require any configuration', async () => {
            // uBlock Origin works out of the box with default filter lists
            const { EXTENSION } = require('../on_Snapshot__03_ublock.js');

            assert.ok(EXTENSION);
            // No config fields should be required
        });

        it('should have large download size (filter lists)', () => {
            // uBlock Origin is typically larger than other extensions
            // due to included filter lists (usually 3-5 MB)

            const typicalSize = 4 * 1024 * 1024; // ~4 MB
            const minExpectedSize = 2 * 1024 * 1024; // Minimum 2 MB

            // Just verify we understand the expected size
            assert.ok(typicalSize > minExpectedSize);
        });
    });

    describe('cache file creation', () => {
        beforeEach(() => {
            process.env.CHROME_EXTENSIONS_DIR = TEST_EXTENSIONS_DIR;

            if (!fs.existsSync(TEST_EXTENSIONS_DIR)) {
                fs.mkdirSync(TEST_EXTENSIONS_DIR, { recursive: true });
            }
        });

        afterEach(() => {
            if (fs.existsSync(TEST_EXTENSIONS_DIR)) {
                fs.rmSync(TEST_EXTENSIONS_DIR, { recursive: true });
            }

            delete process.env.CHROME_EXTENSIONS_DIR;
        });

        it('should create cache file with correct structure', async () => {
            const cacheFile = path.join(TEST_EXTENSIONS_DIR, 'ublock.extension.json');

            const mockExtension = {
                webstore_id: 'cjpalhdlnbpafiamejdnhcphjbkeiagm',
                name: 'ublock',
                version: '1.68.0',
                unpacked_path: path.join(TEST_EXTENSIONS_DIR, 'test_ublock'),
                crx_path: path.join(TEST_EXTENSIONS_DIR, 'test_ublock.crx')
            };

            await fs.promises.writeFile(cacheFile, JSON.stringify(mockExtension, null, 2));

            assert.ok(fs.existsSync(cacheFile));

            const cache = JSON.parse(fs.readFileSync(cacheFile, 'utf-8'));
            assert.strictEqual(cache.name, 'ublock');
            assert.strictEqual(cache.webstore_id, 'cjpalhdlnbpafiamejdnhcphjbkeiagm');
        });
    });

    describe('extension functionality', () => {
        it('should work automatically with default filter lists', () => {
            const features = {
                automaticBlocking: true,
                requiresConfiguration: false,
                requiresApiKey: false,
                defaultFilterLists: true,
                blocksAds: true,
                blocksTrackers: true,
                blocksMalware: true
            };

            assert.strictEqual(features.automaticBlocking, true);
            assert.strictEqual(features.requiresConfiguration, false);
            assert.strictEqual(features.requiresApiKey, false);
            assert.strictEqual(features.defaultFilterLists, true);
        });

        it('should not require runtime configuration', () => {
            // uBlock Origin works purely via filter lists and content scripts
            // No API keys or runtime configuration needed

            const requiresRuntimeConfig = false;
            const requiresApiKey = false;

            assert.strictEqual(requiresRuntimeConfig, false);
            assert.strictEqual(requiresApiKey, false);
        });

        it('should support standard filter list formats', () => {
            const supportedFormats = [
                'EasyList',
                'EasyPrivacy',
                'Malware Domains',
                'Peter Lowe\'s List',
                'uBlock Origin filters'
            ];

            assert.ok(supportedFormats.length > 0);
            // Should support multiple filter list formats
        });
    });

    describe('priority and execution order', () => {
        it('should have priority 03 (early)', () => {
            const filename = 'on_Snapshot__03_ublock.js';

            const match = filename.match(/on_Snapshot__(\d+)_/);
            assert.ok(match);

            const priority = parseInt(match[1]);
            assert.strictEqual(priority, 3);
        });

        it('should run before chrome_session (priority 20)', () => {
            const extensionPriority = 3;
            const chromeSessionPriority = 20;

            assert.ok(extensionPriority < chromeSessionPriority);
        });

        it('should run after cookie dismissal extension', () => {
            const ublockPriority = 3;
            const cookiesPriority = 2;

            assert.ok(ublockPriority > cookiesPriority);
        });
    });

    describe('performance considerations', () => {
        it('should benefit from caching due to large size', () => {
            // uBlock Origin's large size makes caching especially important

            const averageDownloadTime = 10; // seconds
            const averageCacheCheckTime = 0.01; // seconds

            const performanceGain = averageDownloadTime / averageCacheCheckTime;

            // Should be at least 100x faster with cache
            assert.ok(performanceGain > 100);
        });

        it('should not impact page load time significantly', () => {
            // While extension is large, it uses efficient blocking

            const efficientBlocking = true;
            const minimalOverhead = true;

            assert.strictEqual(efficientBlocking, true);
            assert.strictEqual(minimalOverhead, true);
        });
    });

    describe('error handling', () => {
        beforeEach(() => {
            process.env.CHROME_EXTENSIONS_DIR = TEST_EXTENSIONS_DIR;

            if (!fs.existsSync(TEST_EXTENSIONS_DIR)) {
                fs.mkdirSync(TEST_EXTENSIONS_DIR, { recursive: true });
            }
        });

        afterEach(() => {
            if (fs.existsSync(TEST_EXTENSIONS_DIR)) {
                fs.rmSync(TEST_EXTENSIONS_DIR, { recursive: true });
            }

            delete process.env.CHROME_EXTENSIONS_DIR;
        });

        it('should handle corrupted cache gracefully', async () => {
            const cacheFile = path.join(TEST_EXTENSIONS_DIR, 'ublock.extension.json');

            // Create corrupted cache
            fs.writeFileSync(cacheFile, 'invalid json content');

            const { installUblockExtension } = require('../on_Snapshot__03_ublock.js');

            // Mock loadOrInstallExtension to avoid actual download
            const extensionUtils = require('../../chrome_extensions/chrome_extension_utils.js');
            const originalFunc = extensionUtils.loadOrInstallExtension;

            extensionUtils.loadOrInstallExtension = async () => ({
                webstore_id: 'cjpalhdlnbpafiamejdnhcphjbkeiagm',
                name: 'ublock',
                version: '1.68.0'
            });

            const result = await installUblockExtension();

            extensionUtils.loadOrInstallExtension = originalFunc;

            assert.notStrictEqual(result, null);
        });

        it('should handle download timeout gracefully', () => {
            // For large extension like uBlock, timeout handling is important

            const timeoutSeconds = 120; // 2 minutes
            const minTimeout = 30; // Should allow at least 30 seconds

            assert.ok(timeoutSeconds > minTimeout);
        });
    });

    describe('filter list validation', () => {
        it('should have valid filter list format', () => {
            // Example filter list entry
            const sampleFilters = [
                '||ads.example.com^',
                '||tracker.example.com^$third-party',
                '##.advertisement'
            ];

            // All filters should follow standard format
            sampleFilters.forEach(filter => {
                assert.ok(typeof filter === 'string');
                assert.ok(filter.length > 0);
            });
        });

        it('should support cosmetic filters', () => {
            const cosmeticFilter = '##.banner-ad';

            // Should start with ## for cosmetic filters
            assert.ok(cosmeticFilter.startsWith('##'));
        });

        it('should support network filters', () => {
            const networkFilter = '||ads.example.com^';

            // Network filters typically start with || or contain ^
            assert.ok(networkFilter.includes('||') || networkFilter.includes('^'));
        });
    });
});
