// Filename: frontend/js/pages/logs/index.js
import { apiFetchJson } from '../../services/api.js';
import LogList from './logList.js';
import CustomSelectV2 from '../../components/customSelectV2.js';
import { debounce } from '../../utils/utils.js';
import FilterPopover from '../../components/filterPopover.js';
import { STATIC_ERROR_MAP, STATUS_CODE_MAP } from './logList.js';
import SystemLogTerminal from './systemLog.js';
import { initBatchActions } from './batchActions.js'; 
import flatpickr from '../../vendor/flatpickr.js'; 

const dataStore = {
    groups: new Map(),
    keys: new Map(),
}; 
class LogsPage {
    constructor() {
        this.state = {
            logs: [],
            pagination: { page: 1, pages: 1, total: 0, page_size: 20 },
            isLoading: true,
            filters: {
                page: 1,
                page_size: 20,
                q: '',
                key_ids: new Set(),
                group_ids: new Set(),
                error_types: new Set(),
                status_codes: new Set(),
                start_date: null,
                end_date: null,
            },
            selectedLogIds: new Set(),
            currentView: 'error', 
        };
        this.elements = {
            tabsContainer: document.querySelector('[data-sliding-tabs-container]'),
            contentContainer: document.getElementById('log-content-container'),
            errorFilters: document.getElementById('error-logs-filters'),
            systemControls: document.getElementById('system-logs-controls'),
            errorTemplate: document.getElementById('error-logs-template'),
            systemTemplate: document.getElementById('system-logs-template'),
        };
        this.initialized = !!this.elements.contentContainer;
        if (this.initialized) {
            this.logList = null;
            this.systemLogTerminal = null;
            this.debouncedLoadAndRender = debounce(() => this.loadAndRenderLogs(), 300);
            this.fp = null;
            this.themeObserver = null; 
        }
    }
    async init() {
        if (!this.initialized) return;
        this._initPermanentEventListeners();
        await this.loadGroupsOnce();
        this.state.currentView = null;
        this.switchToView('error');
    }
    _initPermanentEventListeners() {
        this.elements.tabsContainer.addEventListener('click', (event) => {
            const tabItem = event.target.closest('[data-tab-target]');
            if (!tabItem) return;
            event.preventDefault();
            const viewName = tabItem.dataset.tabTarget;
            if (viewName) {
                this.switchToView(viewName);
            }
        });
    }
    switchToView(viewName) {
        if (this.state.currentView === viewName && this.elements.contentContainer.innerHTML !== '') return;
        if (this.systemLogTerminal) {
            this.systemLogTerminal.disconnect();
            this.systemLogTerminal = null;
        }
        if (this.fp) {
            this.fp.destroy();
            this.fp = null;
        }

        if (this.themeObserver) {
            this.themeObserver.disconnect();
            this.themeObserver = null;
        }

        this.state.currentView = viewName;
        this.elements.contentContainer.innerHTML = '';
        if (viewName === 'error') {
            this.elements.errorFilters.classList.remove('hidden');
            this.elements.systemControls.classList.add('hidden');
            const template = this.elements.errorTemplate.content.cloneNode(true);
            this.elements.contentContainer.appendChild(template);
            requestAnimationFrame(() => {
                this._initErrorLogView();
            });
        } else if (viewName === 'system') {
            this.elements.errorFilters.classList.add('hidden');
            this.elements.systemControls.classList.remove('hidden');
            const template = this.elements.systemTemplate.content.cloneNode(true);
            this.elements.contentContainer.appendChild(template);
            requestAnimationFrame(() => {
                this._initSystemLogView();
            });
        }
    }
    _initErrorLogView() {
        this.elements.tableBody = document.getElementById('logs-table-body');
        this.elements.selectedCount = document.querySelector('.flex-1.text-sm span.font-semibold:nth-child(1)');
        this.elements.totalCount = document.querySelector('.flex-1.text-sm span:last-child');
        this.elements.pageSizeSelect = document.querySelector('[data-component="custom-select-v2"] select');
        this.elements.pageInfo = document.querySelector('.flex.w-\\[100px\\]');
        this.elements.paginationBtns = document.querySelectorAll('[data-pagination-controls] button');
        this.elements.selectAllCheckbox = document.querySelector('thead .table-head-cell input[type="checkbox"]');
        this.elements.searchInput = document.getElementById('log-search-input');
        this.elements.errorTypeFilterBtn = document.getElementById('filter-error-type-btn');
        this.elements.errorCodeFilterBtn = document.getElementById('filter-error-code-btn');
        this.elements.dateRangeFilterBtn = document.getElementById('filter-date-range-btn');
        
        this.logList = new LogList(this.elements.tableBody, dataStore);
        const selectContainer = document.querySelector('[data-component="custom-select-v2"]');
        if (selectContainer) { new CustomSelectV2(selectContainer); }
        
        this.initFilterPopovers();
        this.initDateRangePicker();
        this.initEventListeners();
        this._observeThemeChanges();
        initBatchActions(this);
        this.loadAndRenderLogs();
    }

    _observeThemeChanges() {
        const applyTheme = () => {
            if (!this.fp || !this.fp.calendarContainer) return;
            if (document.documentElement.classList.contains('dark')) {
                this.fp.calendarContainer.classList.add('dark');
            } else {
                this.fp.calendarContainer.classList.remove('dark');
            }
        };
        this.themeObserver = new MutationObserver((mutationsList) => {
            for (const mutation of mutationsList) {
                if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
                    applyTheme();
                }
            }
        });
        this.themeObserver.observe(document.documentElement, { attributes: true });
        
        // 确保初始状态正确
        applyTheme();
    }

    _initSystemLogView() {
        this.systemLogTerminal = new SystemLogTerminal(
            this.elements.contentContainer, 
            this.elements.systemControls
        );
        Swal.fire({
            width: '20rem',
            backdrop: `rgba(0,0,0,0.5)`,
            heightAuto: false,
            customClass: { popup: `swal2-custom-style ${document.documentElement.classList.contains('dark') ? 'swal2-dark' : ''}` },
            title: '系统终端日志',
            text: '您即将连接到实时系统日志流窗口。',
            showCancelButton: true,
            confirmButtonText: '确认',
            cancelButtonText: '取消',
            reverseButtons: false,
            confirmButtonColor: 'rgba(31, 102, 255, 0.8)', 
            cancelButtonColor: '#6b7280', 
            focusConfirm: false,
            focusCancel: false,
            target: '#main-content-wrapper',
        }).then((result) => {
            if (result.isConfirmed) {
                this.systemLogTerminal.connect();
            } else {
                const errorLogTab = Array.from(this.elements.tabsContainer.querySelectorAll('[data-tab-target="error"]'))[0];
                if (errorLogTab) errorLogTab.click();
            }
        });
    }
    initFilterPopovers() {
        const errorTypeOptions = [
            ...Object.values(STATUS_CODE_MAP).map(v => ({ value: v.type, label: v.type })),
            ...Object.values(STATIC_ERROR_MAP).map(v => ({ value: v.type, label: v.type }))
        ];
        const uniqueErrorTypeOptions = Array.from(new Map(errorTypeOptions.map(item => [item.value, item])).values());
        if (this.elements.errorTypeFilterBtn) {
            new FilterPopover(this.elements.errorTypeFilterBtn, uniqueErrorTypeOptions, '筛选错误类型');
        }
        const statusCodeOptions = Object.keys(STATUS_CODE_MAP).map(code => ({ value: code, label: code }));
        if (this.elements.errorCodeFilterBtn) {
            new FilterPopover(this.elements.errorCodeFilterBtn, statusCodeOptions, '筛选状态码');
        }
    }
    initDateRangePicker() {
        if (!this.elements.dateRangeFilterBtn) return;
        const buttonTextSpan = this.elements.dateRangeFilterBtn.querySelector('span');
        const originalText = buttonTextSpan.textContent;
        this.fp = flatpickr(this.elements.dateRangeFilterBtn, {
            mode: 'range',
            dateFormat: 'Y-m-d',
            onClose: (selectedDates) => {
                if (selectedDates.length === 2) {
                    const [start, end] = selectedDates;
                    end.setHours(23, 59, 59, 999); 
                    this.state.filters.start_date = start.toISOString();
                    this.state.filters.end_date = end.toISOString();
                    const startDateStr = start.toISOString().split('T')[0];
                    const endDateStr = end.toISOString().split('T')[0];
                    
                    buttonTextSpan.textContent = `${startDateStr} ~ ${endDateStr}`;
                    this.elements.dateRangeFilterBtn.classList.add('!border-primary', '!text-primary');
                    this.state.filters.page = 1;
                    this.loadAndRenderLogs();
                }
            },
            onReady: (selectedDates, dateStr, instance) => {
                // 暗黑模式和清除按钮的现有逻辑保持不变
                if (document.documentElement.classList.contains('dark')) {
                    instance.calendarContainer.classList.add('dark');
                }
                const clearButton = document.createElement('button');
                clearButton.textContent = '清除';
                clearButton.className = 'button flatpickr-button flatpickr-clear-button';
                clearButton.addEventListener('click', (e) => {
                    e.preventDefault();
                    instance.clear();
                    
                    this.state.filters.start_date = null;
                    this.state.filters.end_date = null;
                    buttonTextSpan.textContent = originalText;
                    this.elements.dateRangeFilterBtn.classList.remove('!border-primary', '!text-primary');
                    
                    this.state.filters.page = 1;
                    this.loadAndRenderLogs();
                    instance.close();
                });
                instance.calendarContainer.appendChild(clearButton);
                const nativeMonthSelect = instance.monthsDropdownContainer;
                if (!nativeMonthSelect) return;
                const monthYearContainer = nativeMonthSelect.parentElement;
                const wrapper = document.createElement('div');
                wrapper.className = 'custom-select-v2-container relative inline-block text-left';
                
                wrapper.innerHTML = `
                    <button type="button" class="custom-select-trigger inline-flex justify-center items-center w-22 gap-x-1.5 rounded-md bg-transparent px-1 py-1 text-xs font-semibold text-foreground shadow-sm ring-0 ring-inset ring-input hover:bg-accent focus:outline-none focus:ring-1 focus:ring-offset-1 focus:ring-offset-background focus:ring-primary" aria-haspopup="true">
                        <span class="truncate"></span>
                    </button>
                `;
                
                const template = document.createElement('template');
                template.className = 'custom-select-panel-template';
                
                template.innerHTML = `
                    <div class="custom-select-panel absolute z-[1000] my-2 w-24 origin-top-right rounded-md bg-popover dark:bg-zinc-900 shadow-lg ring-1 ring-zinc-500/30 ring-opacity-5 focus:outline-none" role="menu" aria-orientation="vertical" tabindex="-1">
                    </div>
                `;
                nativeMonthSelect.classList.add('hidden');
                wrapper.appendChild(nativeMonthSelect);
                wrapper.appendChild(template);
                monthYearContainer.prepend(wrapper);
                const customSelect = new CustomSelectV2(wrapper);
                instance.customMonthSelect = customSelect; 
            },
            onMonthChange: (selectedDates, dateStr, instance) => {
                if (instance.customMonthSelect) {
                    instance.customMonthSelect.updateTriggerText();
                }
            },
        });
    }
    initEventListeners() {
        if (this.elements.pageSizeSelect) {
            this.elements.pageSizeSelect.addEventListener('change', (e) => this.changePageSize(parseInt(e.target.value, 10)));
        }
        if (this.elements.paginationBtns.length >= 4) {
            this.elements.paginationBtns[0].addEventListener('click', () => this.goToPage(1));
            this.elements.paginationBtns[1].addEventListener('click', () => this.goToPage(this.state.pagination.page - 1));
            this.elements.paginationBtns[2].addEventListener('click', () => this.goToPage(this.state.pagination.page + 1));
            this.elements.paginationBtns[3].addEventListener('click', () => this.goToPage(this.state.pagination.pages));
        }
        if (this.elements.selectAllCheckbox) {
            this.elements.selectAllCheckbox.addEventListener('change', (event) => this.handleSelectAllChange(event));
        }
        if (this.elements.tableBody) {
            this.elements.tableBody.addEventListener('change', (event) => {
                if (event.target.type === 'checkbox') this.handleSelectionChange(event.target);
            });
        }
        if (this.elements.searchInput) {
            this.elements.searchInput.addEventListener('input', (event) => this.handleSearchInput(event));
        }
        if (this.elements.errorTypeFilterBtn) {
            this.elements.errorTypeFilterBtn.addEventListener('filter-change', (e) => this.handleFilterChange(e));
        }
        if (this.elements.errorCodeFilterBtn) {
            this.elements.errorCodeFilterBtn.addEventListener('filter-change', (e) => this.handleFilterChange(e));
        }
    }
    handleFilterChange(event) {
        const { filterKey, selected } = event.detail;
        if (filterKey === 'filter-error-type-btn') {
            this.state.filters.error_types = selected;
        } else if (filterKey === 'filter-error-code-btn') {
            this.state.filters.status_codes = selected;
        }
        this.state.filters.page = 1;
        this.loadAndRenderLogs();
    }
    handleSearchInput(event) {
        const searchTerm = event.target.value.trim().toLowerCase();
        this.state.filters.page = 1;
        this.state.filters.q = '';
        this.state.filters.key_ids = new Set();
        this.state.filters.group_ids = new Set();
        if (searchTerm === '') {
            this.debouncedLoadAndRender();
            return;
        }
        const matchedGroupIds = new Set();
        dataStore.groups.forEach(group => {
            if (group.display_name.toLowerCase().includes(searchTerm)) {
                matchedGroupIds.add(group.id);
            }
        });
        const matchedKeyIds = new Set();
        dataStore.keys.forEach(key => {
            if (key.APIKey && key.APIKey.toLowerCase().includes(searchTerm)) {
                matchedKeyIds.add(key.ID);
            }
        });
        if (matchedGroupIds.size > 0) this.state.filters.group_ids = matchedGroupIds;
        if (matchedKeyIds.size > 0) this.state.filters.key_ids = matchedKeyIds;
        if (matchedGroupIds.size === 0 && matchedKeyIds.size === 0) {
            this.state.filters.q = searchTerm;
        }
        this.debouncedLoadAndRender();
    }
    handleSelectionChange(checkbox) {
        const row = checkbox.closest('.table-row');
        if (!row) return;
        const logId = parseInt(row.dataset.logId, 10);
        if (isNaN(logId)) return;
        if (checkbox.checked) {
            this.state.selectedLogIds.add(logId);
        } else {
            this.state.selectedLogIds.delete(logId);
        }
        this.syncSelectionUI();
    }
    handleSelectAllChange(event) {
        const isChecked = event.target.checked;
        this.state.logs.forEach(log => {
            if (isChecked) {
                this.state.selectedLogIds.add(log.ID);
            } else {
                this.state.selectedLogIds.delete(log.ID);
            }
        });
        this.syncRowCheckboxes();
        this.syncSelectionUI();
    }
    syncRowCheckboxes() {
        const isAllChecked = this.elements.selectAllCheckbox.checked;
        this.elements.tableBody.querySelectorAll('input[type="checkbox"]').forEach(cb => {
            cb.checked = isAllChecked;
        });
    }
    syncSelectionUI() {
        if (!this.elements.selectAllCheckbox || !this.elements.selectedCount) return;
        const selectedCount = this.state.selectedLogIds.size;
        const visibleLogsCount = this.state.logs.length;
        
        if (selectedCount === 0) {
            this.elements.selectAllCheckbox.checked = false;
            this.elements.selectAllCheckbox.indeterminate = false;
        } else if (selectedCount < visibleLogsCount) {
            this.elements.selectAllCheckbox.checked = false;
            this.elements.selectAllCheckbox.indeterminate = true;
        } else if (selectedCount === visibleLogsCount && visibleLogsCount > 0) {
            this.elements.selectAllCheckbox.checked = true;
            this.elements.selectAllCheckbox.indeterminate = false;
        }
        
        this.elements.selectedCount.textContent = selectedCount;
        const hasSelection = selectedCount > 0;
        const deleteSelectedBtn = document.getElementById('delete-selected-logs-btn');
        if (deleteSelectedBtn) {
            deleteSelectedBtn.disabled = !hasSelection;
        }
    }
    changePageSize(newSize) {
        this.state.filters.page_size = newSize;
        this.state.filters.page = 1;
        this.loadAndRenderLogs();
    }
    goToPage(page) {
        if (page < 1 || page > this.state.pagination.pages || this.state.isLoading) return;
        this.state.filters.page = page;
        this.loadAndRenderLogs();
    }
    updatePaginationUI() {
        const { page, pages, total } = this.state.pagination;
        if (this.elements.pageInfo) {
            this.elements.pageInfo.textContent = `第 ${page} / ${pages} 页`;
        }
        if (this.elements.totalCount) {
            this.elements.totalCount.textContent = total;
        }
      
        if (this.elements.paginationBtns.length >= 4) {
            const isFirstPage = page === 1;
            const isLastPage = page === pages || pages === 0;
            this.elements.paginationBtns[0].disabled = isFirstPage;
            this.elements.paginationBtns[1].disabled = isFirstPage;
            this.elements.paginationBtns[2].disabled = isLastPage;
            this.elements.paginationBtns[3].disabled = isLastPage;
        }
    }
    async loadGroupsOnce() {
        if (dataStore.groups.size > 0) return;
        try {
            const { success, data } = await apiFetchJson("/admin/keygroups");
            if (success && Array.isArray(data)) {
                data.forEach(group => dataStore.groups.set(group.id, group));
            }
        } catch (error) {
            console.error("Failed to load key groups:", error);
        }
    }
    async loadAndRenderLogs() {
        this.state.isLoading = true;
        this.state.selectedLogIds.clear();
        this.logList.renderLoading();
        this.updatePaginationUI();
        this.syncSelectionUI();
        try {
            const finalParams = {};
            const { filters } = this.state;
        
            Object.keys(filters).forEach(key => {
                if (!(filters[key] instanceof Set)) {
                    finalParams[key] = filters[key];
                }
            });
            const translatedErrorCodes = new Set(); 
            const translatedStatusCodes = new Set(filters.status_codes); 
            if (filters.error_types.size > 0) {
                filters.error_types.forEach(type => {
                    for (const [code, obj] of Object.entries(STATUS_CODE_MAP)) {
                        if (obj.type === type) translatedStatusCodes.add(code);
                    }
                    for (const [code, obj] of Object.entries(STATIC_ERROR_MAP)) {
                        if (obj.type === type) translatedErrorCodes.add(code);
                    }
                });
            }
            
            if (filters.key_ids.size > 0) finalParams.key_ids = [...filters.key_ids].join(',');
            if (filters.group_ids.size > 0) finalParams.group_ids = [...filters.group_ids].join(',');
            if (translatedErrorCodes.size > 0) finalParams.error_codes = [...translatedErrorCodes].join(',');
            if (translatedStatusCodes.size > 0) finalParams.status_codes = [...translatedStatusCodes].join(',');
            
            Object.keys(finalParams).forEach(key => {
                if (finalParams[key] === '' || finalParams[key] === null || finalParams[key] === undefined) {
                    delete finalParams[key];
                }
            });
            const query = new URLSearchParams(finalParams);
            
            const { success, data } = await apiFetchJson(
                `/admin/logs?${query.toString()}`,
                { cache: 'no-cache', noCache: true }
            );
            if (success && typeof data === 'object' && data.items) {
                const { items, total, page, page_size } = data;
                this.state.logs = items;
                const totalPages = Math.ceil(total / page_size);
                this.state.pagination = { page, page_size, total, pages: totalPages > 0 ? totalPages : 1 };
                await this.enrichLogsWithKeyNames(items);
                this.logList.render(this.state.logs, this.state.pagination, this.state.selectedLogIds);
            } else {
                this.state.logs = [];
                this.state.pagination = { ...this.state.pagination, total: 0, pages: 1, page: 1 };
                this.logList.render([], this.state.pagination);
            }
        } catch (error) {
            console.error("Failed to load logs:", error);
            this.state.logs = [];
            this.state.pagination = { ...this.state.pagination, total: 0, pages: 1, page: 1 };
            this.logList.render([], this.state.pagination);
        } finally {
            this.state.isLoading = false;
            this.updatePaginationUI();
            this.syncSelectionUI();
        }
    }
    async enrichLogsWithKeyNames(logs) {
        const missingKeyIds = [...new Set(
            logs.filter(log => log.KeyID && !dataStore.keys.has(log.KeyID)).map(log => log.ID)
        )];
        if (missingKeyIds.length === 0) return;
        try {
            const idsQuery = missingKeyIds.join(',');
            const { success, data } = await apiFetchJson(`/admin/apikeys?ids=${idsQuery}`);
            if (success && Array.isArray(data)) {
                data.forEach(key => dataStore.keys.set(key.ID, key));
            }
        } catch (error) {
            console.error(`Failed to fetch key details:`, error);
        }
    }
}
export default function() {
    const page = new LogsPage();
    page.init();
}