#!/usr/bin/env node

/**
 * HTML Editor Test Runner
 *
 * This script provides a test environment for our HTML editor functionality
 * using puppeteer for headless browser testing.
 */

const fs = require('fs');
const path = require('path');

// Simple test framework
class TestRunner {
    constructor() {
        this.tests = [];
        this.results = [];
        this.currentTest = null;
    }

    describe(description, testFn) {
        console.log(`\n📋 Test Suite: ${description}`);
        console.log('━'.repeat(50));
        testFn();
    }

    it(description, testFn) {
        this.tests.push({ description, testFn });
    }

    async run() {
        console.log(`\n🚀 Running ${this.tests.length} tests...\n`);

        for (const test of this.tests) {
            this.currentTest = test;
            try {
                console.log(`  🧪 ${test.description}`);
                await test.testFn();
                this.results.push({ ...test, status: 'PASS' });
                console.log(`     ✅ PASS`);
            } catch (error) {
                this.results.push({ ...test, status: 'FAIL', error });
                console.log(`     ❌ FAIL: ${error.message}`);
            }
        }

        this.printSummary();
    }

    printSummary() {
        const passed = this.results.filter(r => r.status === 'PASS').length;
        const failed = this.results.filter(r => r.status === 'FAIL').length;

        console.log('\n' + '═'.repeat(50));
        console.log(`📊 Test Results: ${passed} passed, ${failed} failed`);

        if (failed > 0) {
            console.log('\n❌ Failed Tests:');
            this.results.filter(r => r.status === 'FAIL').forEach(test => {
                console.log(`  • ${test.description}: ${test.error.message}`);
            });
        }

        console.log('═'.repeat(50));
    }

    expect(actual) {
        const expectObj = {
            toBe: (expected) => {
                if (actual !== expected) {
                    throw new Error(`Expected ${expected}, got ${actual}`);
                }
            },
            toContain: (expected) => {
                if (!actual.includes(expected)) {
                    throw new Error(`Expected "${actual}" to contain "${expected}"`);
                }
            },
            toBeTruthy: () => {
                if (!actual) {
                    throw new Error(`Expected truthy value, got ${actual}`);
                }
            },
            toBeFalsy: () => {
                if (actual) {
                    throw new Error(`Expected falsy value, got ${actual}`);
                }
            },
            toBeGreaterThan: (expected) => {
                if (actual <= expected) {
                    throw new Error(`Expected ${actual} to be greater than ${expected}`);
                }
            },
            toBeGreaterThanOrEqual: (expected) => {
                if (actual < expected) {
                    throw new Error(`Expected ${actual} to be greater than or equal to ${expected}`);
                }
            },
            toBeLessThan: (expected) => {
                if (actual >= expected) {
                    throw new Error(`Expected ${actual} to be less than ${expected}`);
                }
            }
        };

        // Add 'not' property for negation
        expectObj.not = {
            toBe: (expected) => {
                if (actual === expected) {
                    throw new Error(`Expected ${actual} not to be ${expected}`);
                }
            },
            toContain: (expected) => {
                if (actual.includes(expected)) {
                    throw new Error(`Expected "${actual}" not to contain "${expected}"`);
                }
            },
            toBeTruthy: () => {
                if (actual) {
                    throw new Error(`Expected falsy value, got ${actual}`);
                }
            },
            toBeFalsy: () => {
                if (!actual) {
                    throw new Error(`Expected truthy value, got ${actual}`);
                }
            }
        };

        return expectObj;
    }
}

// HTML File Tester
class HTMLFileTester {
    constructor(htmlFilePath) {
        this.htmlFilePath = htmlFilePath;
        this.html = null;
        this.jsdom = null;
        this.window = null;
        this.document = null;
    }

    async load() {
        try {
            // Try to use jsdom if available
            const { JSDOM } = require('jsdom');
            this.html = fs.readFileSync(this.htmlFilePath, 'utf8');

            // Create a DOM environment
            this.jsdom = new JSDOM(this.html, {
                runScripts: "dangerously",
                resources: "usable",
                pretendToBeVisual: true
            });

            this.window = this.jsdom.window;
            this.document = this.window.document;

            // Wait for content to load
            await new Promise(resolve => {
                if (this.document.readyState === 'complete') {
                    resolve();
                } else {
                    this.window.addEventListener('load', resolve);
                }
            });

            return true;
        } catch (error) {
            // Fallback to simple HTML parsing
            this.html = fs.readFileSync(this.htmlFilePath, 'utf8');
            console.log('⚠️  Using fallback HTML parsing (install jsdom for full testing)');
            return false;
        }
    }

    hasElement(selector) {
        if (this.document) {
            return !!this.document.querySelector(selector);
        }
        // Fallback: simple text search
        return this.html.includes(selector);
    }

    getElement(selector) {
        if (this.document) {
            return this.document.querySelector(selector);
        }
        return null;
    }

    hasJavaScript(functionName) {
        return this.html.includes(functionName);
    }

    hasDebugMode() {
        return this.html.includes('DEBUG_MODE');
    }

    getDebugMode() {
        const match = this.html.match(/const DEBUG_MODE = ['"`](\w+)['"`];/);
        return match ? match[1] : null;
    }

    simulate(action, selector) {
        if (!this.document) {
            throw new Error('Cannot simulate actions without DOM environment');
        }

        const element = this.document.querySelector(selector);
        if (!element) {
            throw new Error(`Element not found: ${selector}`);
        }

        switch (action) {
            case 'click':
                element.click();
                break;
            case 'focus':
                element.focus();
                break;
            default:
                throw new Error(`Unknown action: ${action}`);
        }
    }
}

// Main test runner instance
const runner = new TestRunner();

// Export for use
module.exports = { TestRunner, HTMLFileTester, runner };

// If run directly, run basic tests
if (require.main === module) {
    console.log('🧪 HTML Editor Test Runner');
    console.log('Usage: node test_runner.js [html-file-path]');

    const htmlFile = process.argv[2] || '/tmp/test_complete_functionality.html';

    if (!fs.existsSync(htmlFile)) {
        console.error(`❌ File not found: ${htmlFile}`);
        process.exit(1);
    }

    // Basic structural tests
    runner.describe('HTML Structure Tests', () => {
        let tester;

        runner.it('should load HTML file successfully', async () => {
            tester = new HTMLFileTester(htmlFile);
            const loaded = await tester.load();
            runner.expect(loaded || tester.html).toBeTruthy();
        });

        runner.it('should have markdown content container', async () => {
            runner.expect(tester.hasElement('#markdown-content')).toBeTruthy();
        });

        runner.it('should have debug system', async () => {
            runner.expect(tester.hasDebugMode()).toBeTruthy();
        });

        runner.it('should use console debug mode', async () => {
            runner.expect(tester.getDebugMode()).toBe('console');
        });

        runner.it('should have section editor functions', async () => {
            runner.expect(tester.hasJavaScript('MarkitectCleanEditor')).toBeTruthy();
            runner.expect(tester.hasJavaScript('showImageEditor')).toBeTruthy();
            runner.expect(tester.hasJavaScript('setupAutoResize')).toBeTruthy();
        });

        runner.it('should have image manipulation functions', async () => {
            runner.expect(tester.hasJavaScript('replaceImage')).toBeTruthy();
            runner.expect(tester.hasJavaScript('resizeImage')).toBeTruthy();
            runner.expect(tester.hasJavaScript('addImageCaption')).toBeTruthy();
            runner.expect(tester.hasJavaScript('removeImage')).toBeTruthy();
        });
    });

    // Run the tests
    runner.run().then(() => {
        console.log('\n🏁 Testing complete!');
    }).catch(error => {
        console.error('❌ Test runner failed:', error);
        process.exit(1);
    });
}