#!/usr/bin/env node
/**
 * History Page UI Tests
 *
 * Tests for the research history page and its functionality.
 *
 * Run: node test_history_page_ci.js
 */
const { setupTest, teardownTest, TestResults, log, delay, navigateTo, withTimeout } = require('./test_lib');

// ============================================================================
// History Page Structure Tests
// ============================================================================
const HistoryPageTests = {
    async historyPageLoads(page, baseUrl) {
        await navigateTo(page, `${baseUrl}/history`);

        const result = await page.evaluate(() => {
            return {
                hasContent: !!document.querySelector('.history-container, .ldr-history, #history, .research-history'),
                hasHeader: !!document.querySelector('h1, .history-header, .page-title'),
                headerText: document.querySelector('h1, .history-header, .page-title')?.textContent?.trim(),
                hasTable: !!document.querySelector('table, .history-table, .ldr-history-list'),
                hasItems: document.querySelectorAll('.history-item, .research-item, tr[data-id], [data-research-id]').length,
                hasEmptyState: !!document.querySelector('.ldr-empty-state, .no-history, .alert-info')
            };
        });

        const passed = result.hasContent || result.hasHeader || result.hasTable || result.hasEmptyState;
        return {
            passed,
            message: passed
                ? `History page loaded (header: "${result.headerText}", items: ${result.hasItems})`
                : 'History page failed to load'
        };
    },

    async historyTableStructure(page, baseUrl) {
        await navigateTo(page, `${baseUrl}/history`);

        // Wait for JS to render history items from API
        await page.waitForFunction(
            () => document.querySelectorAll('.ldr-history-item, .history-item, [data-research-id], table tbody tr').length > 0
                || document.querySelector('.ldr-empty-state, .no-results'),
            { timeout: 5000 }
        ).catch(() => {});

        const result = await page.evaluate(() => {
            const table = document.querySelector('table, .history-table');
            if (table) {
                const headers = Array.from(table.querySelectorAll('th')).map(th => th.textContent?.toLowerCase().trim());
                const rows = table.querySelectorAll('tbody tr, .history-item');
                return {
                    hasTable: true,
                    hasQuery: headers.some(h => h.includes('query') || h.includes('question') || h.includes('topic')),
                    hasMode: headers.some(h => h.includes('mode') || h.includes('type')),
                    hasStatus: headers.some(h => h.includes('status')),
                    hasDate: headers.some(h => h.includes('date') || h.includes('time') || h.includes('created')),
                    hasDuration: headers.some(h => h.includes('duration') || h.includes('time')),
                    headerCount: headers.length,
                    rowCount: rows.length,
                    headers: headers.slice(0, 8)
                };
            }

            // Check for list/card-based layout (ldr-history-list with ldr-history-item)
            const items = document.querySelectorAll('.ldr-history-item, .history-card, .research-card, [data-research-id]');
            if (items.length > 0) {
                return { hasTable: false, hasCards: true, cardCount: items.length };
            }

            return { hasTable: false, hasCards: false };
        });

        if (result.hasTable) {
            return {
                passed: result.hasQuery || result.hasDate,
                message: `History table: ${result.headerCount} columns (${result.headers.join(', ')}), ${result.rowCount} rows`
            };
        }

        if (result.hasCards) {
            return { passed: true, message: `History uses card layout (${result.cardCount} items)` };
        }

        return { passed: null, skipped: true, message: 'No history table or cards found' };
    },

    async historyItemActions(page, baseUrl) {
        await navigateTo(page, `${baseUrl}/history`);

        // Wait for JS to render history items from API
        await page.waitForFunction(
            () => document.querySelectorAll('.ldr-history-item, .history-item, [data-research-id]').length > 0
                || document.querySelector('.ldr-empty-state'),
            { timeout: 5000 }
        ).catch(() => {});

        const result = await page.evaluate(() => {
            const items = document.querySelectorAll('.ldr-history-item, .history-item, .research-item, tr[data-id], [data-research-id]');
            if (items.length === 0) return { hasItems: false };

            const firstItem = items[0];
            const buttons = Array.from(firstItem.querySelectorAll('button, a.btn, .btn, a[href]'));
            const buttonTexts = buttons.map(b => b.textContent?.toLowerCase() || b.title?.toLowerCase() || '');

            return {
                hasItems: true,
                itemCount: items.length,
                hasViewButton: buttonTexts.some(t => t.includes('view') || t.includes('open') || t.includes('results')) ||
                              !!firstItem.querySelector('a[href*="/results/"]'),
                hasDeleteButton: buttonTexts.some(t => t.includes('delete') || t.includes('remove')) ||
                                !!firstItem.querySelector('.btn-danger, .delete-btn'),
                hasExportButton: buttonTexts.some(t => t.includes('export') || t.includes('download')),
                actionCount: buttons.length
            };
        });

        if (!result.hasItems) {
            return { passed: null, skipped: true, message: 'No history items to test actions' };
        }

        const hasActions = result.hasViewButton || result.hasDeleteButton || result.actionCount > 0;
        return {
            passed: hasActions,
            message: hasActions
                ? `History item actions: view=${result.hasViewButton}, delete=${result.hasDeleteButton}, export=${result.hasExportButton} (${result.actionCount} buttons)`
                : 'No action buttons found on history items'
        };
    },

    async clearHistoryButton(page, baseUrl) {
        await navigateTo(page, `${baseUrl}/history`);

        const result = await page.evaluate(() => {
            const buttons = Array.from(document.querySelectorAll('button, a.btn'));
            const clearBtn = buttons.find(b =>
                b.textContent?.toLowerCase().includes('clear') ||
                b.textContent?.toLowerCase().includes('delete all') ||
                b.textContent?.toLowerCase().includes('remove all')
            );

            return {
                hasClearButton: !!clearBtn,
                buttonText: clearBtn?.textContent?.trim()
            };
        });

        if (!result.hasClearButton) {
            return { passed: null, skipped: true, message: 'No clear all history button found' };
        }

        return {
            passed: true,
            message: `Clear history button found ("${result.buttonText}")`
        };
    },

    async historySearchFilter(page, baseUrl) {
        await navigateTo(page, `${baseUrl}/history`);

        const result = await page.evaluate(() => {
            const searchInput = document.querySelector(
                'input[type="search"], ' +
                'input[placeholder*="search"], ' +
                'input[placeholder*="filter"], ' +
                '#history-search, ' +
                '.history-filter'
            );

            const filterSelect = document.querySelector(
                'select[name*="filter"], ' +
                'select[name*="status"], ' +
                '.filter-dropdown'
            );

            return {
                hasSearch: !!searchInput,
                searchPlaceholder: searchInput?.placeholder,
                hasFilter: !!filterSelect,
                filterOptions: filterSelect ? Array.from(filterSelect.options).map(o => o.text).slice(0, 5) : []
            };
        });

        const hasAny = result.hasSearch || result.hasFilter;
        if (!hasAny) {
            return { passed: null, skipped: true, message: 'No search/filter functionality on history page' };
        }

        return {
            passed: true,
            message: result.hasSearch
                ? `Search input found (placeholder: "${result.searchPlaceholder}")`
                : `Filter dropdown found (options: ${result.filterOptions.join(', ')})`
        };
    },

    async historyPagination(page, baseUrl) {
        await navigateTo(page, `${baseUrl}/history`);

        const result = await page.evaluate(() => {
            const pagination = document.querySelector('.pagination, .pager, nav[aria-label*="pagination"]');
            const pageLinks = document.querySelectorAll('.page-link, .pagination a, .pagination button');
            const loadMoreBtn = document.querySelector('.load-more, button[onclick*="loadMore"]');

            return {
                hasPagination: !!pagination || pageLinks.length > 0,
                pageCount: pageLinks.length,
                hasLoadMore: !!loadMoreBtn,
                hasNextPrev: !!document.querySelector('[aria-label*="next"], [aria-label*="previous"], .next, .prev')
            };
        });

        if (!result.hasPagination && !result.hasLoadMore) {
            return { passed: null, skipped: true, message: 'No pagination controls (may have few items)' };
        }

        return {
            passed: true,
            message: result.hasPagination
                ? `Pagination found (${result.pageCount} page links, next/prev=${result.hasNextPrev})`
                : 'Load more button found'
        };
    }
};

// ============================================================================
// History API Tests
// ============================================================================
const HistoryApiTests = {
    async historyApiResponds(page, baseUrl) {
        await navigateTo(page, `${baseUrl}/history`);

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

                const data = await response.json();
                return {
                    ok: true,
                    status: response.status,
                    itemCount: Array.isArray(data) ? data.length : (data.items?.length || data.history?.length || 0)
                };
            } catch (e) {
                return { ok: false, error: e.message };
            }
        }, baseUrl);

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

    async historyItemDetailsApi(page, baseUrl) {
        await navigateTo(page, `${baseUrl}/history`);

        // Get first research ID
        const researchId = await page.evaluate(() => {
            const item = document.querySelector('[data-research-id], [data-id], a[href*="/results/"]');
            if (!item) return null;

            return item.dataset?.researchId ||
                   item.dataset?.id ||
                   item.href?.match(/\/results\/(\d+)/)?.[1];
        });

        if (!researchId) {
            return { passed: null, skipped: true, message: 'No research ID found to test details API' };
        }

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

                const data = await response.json();
                return {
                    ok: true,
                    status: response.status,
                    hasQuery: !!data.query,
                    hasStatus: !!data.status
                };
            } catch (e) {
                return { ok: false, error: e.message };
            }
        }, baseUrl, researchId);

        return {
            passed: result.ok,
            message: result.ok
                ? `Research details API responds (query=${result.hasQuery}, status=${result.hasStatus})`
                : `Research details API failed: ${result.error || 'status ' + result.status}`
        };
    }
};

// ============================================================================
// Main Test Runner
// ============================================================================
async function main() {
    log.section('History Page Tests');

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

    const subTestTimeout = ctx.config.isCI ? 60000 : 30000;
    async function run(category, name, testFn) {
        try {
            const result = await withTimeout(
                testFn(page, baseUrl),
                subTestTimeout,
                `${category}/${name}`
            );
            if (result.skipped) {
                results.skip(category, name, result.message);
            } else {
                results.add(category, name, result.passed, result.message);
            }
        } catch (error) {
            results.add(category, name, false, `Error: ${error.message}`);
        }
    }

    try {
        // Page Structure Tests
        log.section('Page Structure');
        await run('Structure', 'History Page Loads', (p, u) => HistoryPageTests.historyPageLoads(p, u));
        await run('Structure', 'History Table Structure', (p, u) => HistoryPageTests.historyTableStructure(p, u));
        await run('Structure', 'History Item Actions', (p, u) => HistoryPageTests.historyItemActions(p, u));
        await run('Structure', 'Clear History Button', (p, u) => HistoryPageTests.clearHistoryButton(p, u));

        // Search/Filter Tests
        log.section('Search & Filter');
        await run('Filter', 'History Search/Filter', (p, u) => HistoryPageTests.historySearchFilter(p, u));
        await run('Filter', 'History Pagination', (p, u) => HistoryPageTests.historyPagination(p, u));

        // API Tests
        log.section('History APIs');
        await run('API', 'History API Responds', (p, u) => HistoryApiTests.historyApiResponds(p, u));
        await run('API', 'Research Details API', (p, u) => HistoryApiTests.historyItemDetailsApi(p, u));

    } catch (error) {
        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 = { HistoryPageTests, HistoryApiTests };
