const { test, expect } = require('@playwright/test');

const EDITOR_LOAD_TIMEOUT = 15000;

async function waitForEditor(page) {
    await page.goto('/', { waitUntil: 'domcontentloaded' });
    await page.waitForFunction(() => window.editor && window.editor.getHtml, { timeout: EDITOR_LOAD_TIMEOUT });
}

// Helper: get block element from the block panel by label
async function getBlockElement(page, label) {
    // GrapesJS blocks have title attributes or contain text matching the label
    return page.locator(`.gjs-block[title="${label}"], .gjs-block:has-text("${label}")`).first();
}

// Helper: get the canvas iframe body
async function getCanvasBody(page) {
    const frame = page.frameLocator('.gjs-frame');
    return frame.locator('body');
}

test.describe('Site Builder Integration Tests', () => {

    test.describe('Block Drag & Drop', () => {

        test('text block can be added to canvas', async ({ page }) => {
            await waitForEditor(page);

            // Use GrapesJS API to add a text block
            const result = await page.evaluate(() => {
                const editor = window.editor;
                const block = editor.BlockManager.get('text-block');
                if (!block) return { error: 'text-block not found' };
                // Add component directly
                const comp = editor.addComponents(block.get('content'));
                return { success: true, count: editor.getComponents().length };
            });

            expect(result.success).toBe(true);
            expect(result.count).toBeGreaterThan(0);
        });

        test('anchor block can be added to canvas', async ({ page }) => {
            await waitForEditor(page);

            const result = await page.evaluate(() => {
                const editor = window.editor;
                const block = editor.BlockManager.get('anchor-point');
                if (!block) return { error: 'anchor-point block not found', blocks: editor.BlockManager.getAll().map(b => b.id) };
                const comp = editor.addComponents(block.get('content'));
                const html = editor.getHtml();
                return { success: true, hasAnchor: html.includes('data-anchor'), html: html.substring(0, 200) };
            });

            expect(result.error).toBeUndefined();
            expect(result.success).toBe(true);
            expect(result.hasAnchor).toBe(true);
        });

        test('image block can be added to canvas', async ({ page }) => {
            await waitForEditor(page);

            const result = await page.evaluate(() => {
                const editor = window.editor;
                const block = editor.BlockManager.get('image-block');
                if (!block) return { error: 'image-block not found' };
                editor.addComponents(block.get('content'));
                return { success: true, hasImg: editor.getHtml().includes('<img') };
            });

            expect(result.success).toBe(true);
            expect(result.hasImg).toBe(true);
        });

        test('video block can be added to canvas', async ({ page }) => {
            await waitForEditor(page);

            const result = await page.evaluate(() => {
                const editor = window.editor;
                const block = editor.BlockManager.get('video-block');
                if (!block) return { error: 'video-block not found' };
                editor.addComponents(block.get('content'));
                return { success: true, hasVideo: editor.getHtml().includes('video-wrapper') };
            });

            expect(result.success).toBe(true);
            expect(result.hasVideo).toBe(true);
        });

        test('all expected blocks are registered', async ({ page }) => {
            await waitForEditor(page);

            const blocks = await page.evaluate(() => {
                return window.editor.BlockManager.getAll().map(b => b.id);
            });

            const expectedBlocks = ['text-block', 'heading', 'button-block', 'anchor-point', 'image-block', 'video-block', 'section', 'footer'];
            for (const name of expectedBlocks) {
                expect(blocks, `Missing block: ${name}`).toContain(name);
            }
        });
    });

    test.describe('Save & Load', () => {

        test('save works with localStorage fallback (no WHP API)', async ({ page }) => {
            await waitForEditor(page);

            // Wait for whpInt to initialize
            await page.waitForFunction(() => !!window.whpInt, { timeout: 10000 });

            // Add some content then save
            const result = await page.evaluate(async () => {
                const editor = window.editor;
                editor.addComponents('<p>Test save content</p>');

                const site = await window.whpInt.saveToWHP(null, 'Test Site');
                const stored = localStorage.getItem('whp-sites');
                return { success: !!site, stored: !!stored, siteName: site?.name };
            });

            expect(result.success).toBe(true);
            expect(result.stored).toBe(true);
            expect(result.siteName).toBe('Test Site');
        });

        test('GrapesJS autosave to localStorage works', async ({ page }) => {
            await waitForEditor(page);

            const result = await page.evaluate(async () => {
                const editor = window.editor;
                editor.addComponents('<p>Autosave test</p>');
                // Trigger storage save and wait
                await editor.store();
                // GrapesJS may use a different key format
                const keys = Object.keys(localStorage).filter(k => k.includes('sitebuilder') || k.includes('gjsProject'));
                const stored = keys.length > 0 || !!localStorage.getItem('sitebuilder-project');
                return { hasData: stored, keys };
            });

            expect(result.hasData).toBe(true);
        });
    });

    test.describe('Asset Management', () => {

        test('asset manager initializes', async ({ page }) => {
            await waitForEditor(page);

            const result = await page.evaluate(() => {
                return {
                    hasAssetManager: !!window.assetManager,
                    assetsArray: Array.isArray(window.assetManager?.assets)
                };
            });

            expect(result.hasAssetManager).toBe(true);
            expect(result.assetsArray).toBe(true);
        });

        test('can add image asset programmatically', async ({ page }) => {
            await waitForEditor(page);

            const result = await page.evaluate(() => {
                const am = window.assetManager;
                if (!am) return { error: 'no asset manager' };
                const asset = am.addAssetUrl('https://example.com/photo.jpg');
                return { type: asset.type, name: asset.name, count: am.assets.length };
            });

            expect(result.type).toBe('image');
            expect(result.name).toBe('photo.jpg');
            expect(result.count).toBeGreaterThan(0);
        });

        test('can add video asset programmatically', async ({ page }) => {
            await waitForEditor(page);

            const result = await page.evaluate(() => {
                const am = window.assetManager;
                if (!am) return { error: 'no asset manager' };
                const asset = am.addAssetUrl('https://example.com/clip.mp4');
                return { type: asset.type, name: asset.name };
            });

            expect(result.type).toBe('video');
            expect(result.name).toBe('clip.mp4');
        });

        test('asset browser filters video assets correctly', async ({ page }) => {
            await waitForEditor(page);

            const result = await page.evaluate(() => {
                const am = window.assetManager;
                if (!am) return { error: 'no asset manager' };
                // Clear and add test assets
                am.assets = [];
                am.addAssetUrl('https://example.com/photo.jpg');
                am.addAssetUrl('https://example.com/clip.mp4');
                am.addAssetUrl('https://example.com/movie.webm');
                am.addAssetUrl('https://example.com/style.css');

                const videoAssets = am.assets.filter(a => a.type === 'video' || (a.url && a.url.match(/\.(mp4|webm|ogg|mov|avi)$/i)));
                const imageAssets = am.assets.filter(a => a.type === 'image');
                return { videos: videoAssets.length, images: imageAssets.length, total: am.assets.length };
            });

            expect(result.videos).toBe(2);
            expect(result.images).toBe(1);
            expect(result.total).toBe(4);
        });

        test('asset browser modal opens and shows assets', async ({ page }) => {
            await waitForEditor(page);

            // Add assets then open browser
            await page.evaluate(() => {
                const am = window.assetManager;
                am.assets = [];
                am.addAssetUrl('https://example.com/photo.jpg');
                am.addAssetUrl('https://example.com/clip.mp4');
            });

            // Open the browser for images
            await page.evaluate(() => {
                window.assetManager.openBrowser('image');
            });

            // Modal should be visible
            const modal = page.locator('#asset-browser-modal.visible');
            await expect(modal).toBeVisible({ timeout: 3000 });

            // Should show image items
            const items = page.locator('#asset-browser-grid .asset-browser-item');
            await expect(items).toHaveCount(1);

            // Switch to video tab
            await page.click('.asset-tab[data-type="video"]');
            await expect(items).toHaveCount(1);

            // Switch to all tab
            await page.click('.asset-tab[data-type="all"]');
            await expect(items).toHaveCount(2);
        });
    });

    test.describe('Templates', () => {

        test('template list loads', async ({ page }) => {
            await waitForEditor(page);

            // Check if template modal button exists
            const templateBtn = page.locator('#btn-templates, button:has-text("Templates")');
            const exists = await templateBtn.count();
            expect(exists).toBeGreaterThan(0);
        });
    });

    test.describe('Export', () => {

        test('can export HTML', async ({ page }) => {
            await waitForEditor(page);

            // Add content and export
            const result = await page.evaluate(() => {
                const editor = window.editor;
                editor.addComponents('<p>Export test content</p>');
                const html = editor.getHtml();
                const css = editor.getCss();
                return { hasHtml: html.length > 0, hasCss: typeof css === 'string', htmlContains: html.includes('Export test content') };
            });

            expect(result.hasHtml).toBe(true);
            expect(result.hasCss).toBe(true);
            expect(result.htmlContains).toBe(true);
        });
    });

    test.describe('Editor Core', () => {

        test('editor loads without errors', async ({ page }) => {
            const errors = [];
            page.on('pageerror', err => errors.push(err.message));

            await waitForEditor(page);

            // Filter out non-critical errors (network errors for fonts etc are ok)
            const criticalErrors = errors.filter(e => !e.includes('net::') && !e.includes('Failed to load resource'));
            expect(criticalErrors).toHaveLength(0);
        });

        test('canvas iframe is present', async ({ page }) => {
            await waitForEditor(page);
            const frame = page.locator('.gjs-frame');
            await expect(frame).toBeVisible();
        });

        test('block panel is visible', async ({ page }) => {
            await waitForEditor(page);
            const blocks = page.locator('#blocks-container .gjs-block');
            const count = await blocks.count();
            expect(count).toBeGreaterThan(5);
        });
    });
});
