#!/usr/bin/env node
/**
 * Library & Collections UI Tests
 *
 * Tests for the library page, collections management, and document viewing.
 *
 * Run: node test_library_collections_ci.js
 */

const { setupTest, teardownTest, TestResults, log, delay } = require('./test_lib');

// ============================================================================
// Library Page Tests
// ============================================================================
const LibraryPageTests = {
    async libraryPageLoads(page, baseUrl) {
        await page.goto(`${baseUrl}/library`, { waitUntil: 'networkidle2' });

        const result = await page.evaluate(() => {
            return {
                hasLibraryContent: !!document.querySelector('.library-container, .ldr-library, #library, .document-list'),
                hasHeader: !!document.querySelector('h1, .library-header, .page-title'),
                headerText: document.querySelector('h1, .library-header, .page-title')?.textContent?.trim(),
                hasDocuments: document.querySelectorAll('.document-item, .library-item, tr[data-id], .ldr-document').length,
                hasTable: !!document.querySelector('table, .document-table')
            };
        });

        const passed = result.hasLibraryContent || result.hasHeader || result.hasTable;
        return {
            passed,
            message: passed
                ? `Library page loaded (header: "${result.headerText}", documents: ${result.hasDocuments})`
                : 'Library page failed to load'
        };
    },

    async libraryHeaderButtons(page, baseUrl) {
        await page.goto(`${baseUrl}/library`, { waitUntil: 'networkidle2' });

        const result = await page.evaluate(() => {
            const buttons = Array.from(document.querySelectorAll('button, a.btn, .btn'));
            const buttonTexts = buttons.map(b => b.textContent?.toLowerCase() || '');

            return {
                hasSyncButton: buttonTexts.some(t => t.includes('sync')),
                hasGetPdfsButton: buttonTexts.some(t => t.includes('pdf') || t.includes('download')),
                hasTextOnlyButton: buttonTexts.some(t => t.includes('text') || t.includes('extract')),
                hasUploadButton: buttonTexts.some(t => t.includes('upload')),
                buttonCount: buttons.length,
                foundButtons: buttonTexts.filter(t => t.length > 0 && t.length < 50).slice(0, 8)
            };
        });

        const hasAnyButton = result.hasSyncButton || result.hasGetPdfsButton || result.hasUploadButton;
        return {
            passed: hasAnyButton,
            message: hasAnyButton
                ? `Library buttons found: sync=${result.hasSyncButton}, pdfs=${result.hasGetPdfsButton}, upload=${result.hasUploadButton}`
                : `No expected buttons found. Found: ${result.foundButtons.join(', ')}`
        };
    },

    async storageModeBadge(page, baseUrl) {
        await page.goto(`${baseUrl}/library`, { waitUntil: 'networkidle2' });

        const result = await page.evaluate(() => {
            const badge = document.querySelector(
                '.storage-mode, ' +
                '.badge[class*="storage"], ' +
                '[data-storage-mode], ' +
                '.ldr-storage-badge'
            );

            const storageInfo = document.querySelector('.storage-info, .library-stats, .storage-status');

            return {
                hasBadge: !!badge,
                badgeText: badge?.textContent?.trim(),
                hasStorageInfo: !!storageInfo,
                storageInfoText: storageInfo?.textContent?.trim().substring(0, 100)
            };
        });

        if (!result.hasBadge && !result.hasStorageInfo) {
            return { passed: null, skipped: true, message: 'No storage mode indicator found' };
        }

        return {
            passed: true,
            message: result.hasBadge
                ? `Storage mode badge: "${result.badgeText}"`
                : `Storage info displayed: "${result.storageInfoText}"`
        };
    },

    async collectionFilterDropdown(page, baseUrl) {
        await page.goto(`${baseUrl}/library`, { waitUntil: 'networkidle2' });

        const result = await page.evaluate(() => {
            const collectionFilter = document.querySelector(
                'select[name*="collection"], ' +
                '#collection-filter, ' +
                '.collection-filter, ' +
                'select.ldr-filter'
            );

            if (!collectionFilter) return { exists: false };

            const options = Array.from(collectionFilter.options);
            return {
                exists: true,
                optionCount: options.length,
                options: options.map(o => o.text).slice(0, 8)
            };
        });

        if (!result.exists) {
            return { passed: null, skipped: true, message: 'No collection filter dropdown found' };
        }

        return {
            passed: result.optionCount > 0,
            message: `Collection filter has ${result.optionCount} options: ${result.options.join(', ')}`
        };
    },

    async statusFilterDropdown(page, baseUrl) {
        await page.goto(`${baseUrl}/library`, { waitUntil: 'networkidle2' });

        const result = await page.evaluate(() => {
            const statusFilter = document.querySelector(
                'select[name*="status"], ' +
                '#status-filter, ' +
                '.status-filter'
            );

            if (!statusFilter) return { exists: false };

            const options = Array.from(statusFilter.options);
            return {
                exists: true,
                optionCount: options.length,
                options: options.map(o => o.text).slice(0, 8)
            };
        });

        if (!result.exists) {
            return { passed: null, skipped: true, message: 'No status filter dropdown found' };
        }

        return {
            passed: result.optionCount > 0,
            message: `Status filter has ${result.optionCount} options: ${result.options.join(', ')}`
        };
    }
};

// ============================================================================
// Collections Page Tests
// ============================================================================
const CollectionsPageTests = {
    async collectionsPageLoads(page, baseUrl) {
        await page.goto(`${baseUrl}/library/collections`, { waitUntil: 'networkidle2' });

        const result = await page.evaluate(() => {
            return {
                hasContent: !!document.querySelector('.collections-container, .ldr-collections, #collections, .collection-list'),
                hasHeader: !!document.querySelector('h1, .collections-header, .page-title'),
                headerText: document.querySelector('h1, .collections-header, .page-title')?.textContent?.trim(),
                collectionCount: document.querySelectorAll('.collection-card, .collection-item, [data-collection-id]').length
            };
        });

        const passed = result.hasContent || result.hasHeader;
        return {
            passed,
            message: passed
                ? `Collections page loaded (header: "${result.headerText}", collections: ${result.collectionCount})`
                : 'Collections page failed to load'
        };
    },

    async createCollectionButton(page, baseUrl) {
        await page.goto(`${baseUrl}/library/collections`, { waitUntil: 'networkidle2' });

        const result = await page.evaluate(() => {
            const buttons = Array.from(document.querySelectorAll('button, a.btn, .btn'));
            const createBtn = buttons.find(b =>
                b.textContent?.toLowerCase().includes('create') ||
                b.textContent?.toLowerCase().includes('new') ||
                b.textContent?.toLowerCase().includes('add')
            );

            return {
                hasCreateButton: !!createBtn,
                buttonText: createBtn?.textContent?.trim()
            };
        });

        return {
            passed: result.hasCreateButton,
            message: result.hasCreateButton
                ? `Create collection button found ("${result.buttonText}")`
                : 'No create collection button found'
        };
    },

    async collectionCardStructure(page, baseUrl) {
        await page.goto(`${baseUrl}/library/collections`, { waitUntil: 'networkidle2' });

        const result = await page.evaluate(() => {
            const cards = document.querySelectorAll('.collection-card, .collection-item, [data-collection-id]');
            if (cards.length === 0) return { hasCards: false };

            const firstCard = cards[0];
            return {
                hasCards: true,
                cardCount: cards.length,
                hasName: !!firstCard.querySelector('.collection-name, .card-title, h3, h4, .name'),
                hasCount: !!firstCard.querySelector('.document-count, .count, .badge'),
                hasActions: !!firstCard.querySelector('.card-actions, .btn, button, .actions')
            };
        });

        if (!result.hasCards) {
            return { passed: null, skipped: true, message: 'No collections to test card structure' };
        }

        const hasRequiredParts = result.hasName;
        return {
            passed: hasRequiredParts,
            message: hasRequiredParts
                ? `Collection cards: ${result.cardCount} found (name=${result.hasName}, count=${result.hasCount}, actions=${result.hasActions})`
                : 'Collection cards missing required elements'
        };
    },

    async uploadDocumentButton(page, baseUrl) {
        await page.goto(`${baseUrl}/library/collections`, { waitUntil: 'networkidle2' });

        const result = await page.evaluate(() => {
            const uploadBtn = document.querySelector(
                'button[onclick*="upload"], ' +
                'a[href*="upload"], ' +
                '.upload-btn, ' +
                'input[type="file"]'
            );

            const buttons = Array.from(document.querySelectorAll('button, a.btn'));
            const uploadByText = buttons.find(b => b.textContent?.toLowerCase().includes('upload'));

            return {
                hasUploadButton: !!uploadBtn || !!uploadByText,
                buttonText: (uploadBtn || uploadByText)?.textContent?.trim(),
                hasFileInput: !!document.querySelector('input[type="file"]')
            };
        });

        if (!result.hasUploadButton && !result.hasFileInput) {
            return { passed: null, skipped: true, message: 'No upload functionality found on collections page' };
        }

        return {
            passed: true,
            message: result.hasUploadButton
                ? `Upload button found ("${result.buttonText}")`
                : 'File input found for uploads'
        };
    }
};

// ============================================================================
// Document Details Tests
// ============================================================================
const DocumentTests = {
    async documentDetailsPage(page, baseUrl) {
        // First check if there are any documents
        await page.goto(`${baseUrl}/library`, { waitUntil: 'networkidle2' });

        const docLink = await page.evaluate(() => {
            const link = document.querySelector('a[href*="/documents/"], a[href*="/document/"]');
            return link?.href;
        });

        if (!docLink) {
            return { passed: null, skipped: true, message: 'No documents to test details page' };
        }

        await page.goto(docLink, { waitUntil: 'networkidle2' });

        const result = await page.evaluate(() => {
            return {
                hasTitle: !!document.querySelector('h1, .document-title, .page-title'),
                titleText: document.querySelector('h1, .document-title, .page-title')?.textContent?.trim(),
                hasMetadata: !!document.querySelector('.metadata, .document-info, .details'),
                hasContent: !!document.querySelector('.document-content, .text-content, .content, pre, .markdown'),
                hasBackButton: !!document.querySelector('a[href*="/library"], .back-btn, .btn-back')
            };
        });

        const passed = result.hasTitle || result.hasContent;
        return {
            passed,
            message: passed
                ? `Document details page loaded (title: "${result.titleText?.substring(0, 30)}", metadata=${result.hasMetadata}, content=${result.hasContent})`
                : 'Document details page missing expected elements'
        };
    }
};

// ============================================================================
// Library API Tests
// ============================================================================
const LibraryApiTests = {
    async libraryApiResponds(page, baseUrl) {
        await page.goto(`${baseUrl}/library`, { waitUntil: 'networkidle2' });

        const result = await page.evaluate(async (url) => {
            try {
                // Try common library API endpoints
                const endpoints = [
                    '/library/api/documents',
                    '/library/api/collections',
                    '/library/api/collections/list'
                ];

                for (const endpoint of endpoints) {
                    try {
                        const response = await fetch(`${url}${endpoint}`);
                        if (response.ok) {
                            return { ok: true, endpoint, status: response.status };
                        }
                    } catch (e) {
                        continue;
                    }
                }

                return { ok: false, error: 'No library API endpoint responded' };
            } catch (e) {
                return { ok: false, error: e.message };
            }
        }, baseUrl);

        return {
            passed: result.ok,
            message: result.ok
                ? `Library API responds at ${result.endpoint} (status ${result.status})`
                : `Library API check: ${result.error}`
        };
    },

    async collectionsApiResponds(page, baseUrl) {
        await page.goto(`${baseUrl}/library/collections`, { waitUntil: 'networkidle2' });

        const result = await page.evaluate(async (url) => {
            try {
                const response = await fetch(`${url}/library/api/collections`);
                if (!response.ok) return { ok: false, status: response.status };

                const data = await response.json();
                return {
                    ok: true,
                    status: response.status,
                    collectionCount: Array.isArray(data) ? data.length : Object.keys(data).length
                };
            } catch (e) {
                return { ok: false, error: e.message };
            }
        }, baseUrl);

        if (!result.ok && result.status === 404) {
            return { passed: null, skipped: true, message: 'Collections API endpoint not found' };
        }

        return {
            passed: result.ok,
            message: result.ok
                ? `Collections API responds (${result.collectionCount} collections)`
                : `Collections API failed: ${result.error || 'status ' + result.status}`
        };
    }
};

// ============================================================================
// Main Test Runner
// ============================================================================
async function main() {
    log.section('Library & Collections Tests');

    const ctx = await setupTest({ authenticate: true });
    const results = new TestResults('Library & Collections Tests');
    const { page } = ctx;
    const { baseUrl } = ctx.config;

    try {
        // Library Page Tests
        log.section('Library Page');
        await results.run('Library', 'Library Page Loads', () => LibraryPageTests.libraryPageLoads(page, baseUrl), { page });
        await results.run('Library', 'Library Header Buttons', () => LibraryPageTests.libraryHeaderButtons(page, baseUrl), { page });

        const storageBadgeResult = await LibraryPageTests.storageModeBadge(page, baseUrl);
        if (storageBadgeResult.skipped) {
            results.skip('Library', 'Storage Mode Badge', storageBadgeResult.message);
        } else {
            results.add('Library', 'Storage Mode Badge', storageBadgeResult.passed, storageBadgeResult.message);
        }

        const collFilterResult = await LibraryPageTests.collectionFilterDropdown(page, baseUrl);
        if (collFilterResult.skipped) {
            results.skip('Library', 'Collection Filter Dropdown', collFilterResult.message);
        } else {
            results.add('Library', 'Collection Filter Dropdown', collFilterResult.passed, collFilterResult.message);
        }

        const statusFilterResult = await LibraryPageTests.statusFilterDropdown(page, baseUrl);
        if (statusFilterResult.skipped) {
            results.skip('Library', 'Status Filter Dropdown', statusFilterResult.message);
        } else {
            results.add('Library', 'Status Filter Dropdown', statusFilterResult.passed, statusFilterResult.message);
        }

        // Collections Page Tests
        log.section('Collections Page');
        await results.run('Collections', 'Collections Page Loads', () => CollectionsPageTests.collectionsPageLoads(page, baseUrl), { page });
        await results.run('Collections', 'Create Collection Button', () => CollectionsPageTests.createCollectionButton(page, baseUrl), { page });

        const cardResult = await CollectionsPageTests.collectionCardStructure(page, baseUrl);
        if (cardResult.skipped) {
            results.skip('Collections', 'Collection Card Structure', cardResult.message);
        } else {
            results.add('Collections', 'Collection Card Structure', cardResult.passed, cardResult.message);
        }

        const uploadResult = await CollectionsPageTests.uploadDocumentButton(page, baseUrl);
        if (uploadResult.skipped) {
            results.skip('Collections', 'Upload Document Button', uploadResult.message);
        } else {
            results.add('Collections', 'Upload Document Button', uploadResult.passed, uploadResult.message);
        }

        // Document Details Tests
        log.section('Document Details');
        const docDetailsResult = await DocumentTests.documentDetailsPage(page, baseUrl);
        if (docDetailsResult.skipped) {
            results.skip('Documents', 'Document Details Page', docDetailsResult.message);
        } else {
            results.add('Documents', 'Document Details Page', docDetailsResult.passed, docDetailsResult.message);
        }

        // API Tests
        log.section('Library APIs');
        await results.run('API', 'Library API Responds', () => LibraryApiTests.libraryApiResponds(page, baseUrl), { page });

        const collectionsApiResult = await LibraryApiTests.collectionsApiResponds(page, baseUrl);
        if (collectionsApiResult.skipped) {
            results.skip('API', 'Collections API Responds', collectionsApiResult.message);
        } else {
            results.add('API', 'Collections API Responds', collectionsApiResult.passed, collectionsApiResult.message);
        }

    } catch (error) {
        // Check if this is a navigation/browser error (not a real test failure)
        const isNavigationError = error.message &&
            (error.message.includes('context was destroyed') ||
             error.message.includes('Target closed') ||
             error.message.includes('Protocol error') ||
             error.message.includes('Session closed') ||
             error.message.includes('page has been closed'));

        if (isNavigationError) {
            log.warn(`Browser navigation error (test infrastructure issue): ${error.message}`);
            // Don't count as failure - this is a flaky test issue
        } else {
            log.error(`Fatal error: ${error.message}`);
            console.error(error.stack);
        }
    } finally {
        results.print();
        results.save();
        await teardownTest(ctx);
        process.exit(results.exitCode());
    }
}

// Run if executed directly
if (require.main === module) {
    main().catch(error => {
        console.error('Test runner failed:', error);
        process.exit(1);
    });
}

module.exports = { LibraryPageTests, CollectionsPageTests, DocumentTests, LibraryApiTests };
