/**
 * @file taskCenter.js
 * @description Centralizes Task component classes for global.
 * This module exports singleton instances of `TaskCenterManager` and `ToastManager`
 * to ensure consistent task service across the application.
 */
// ===================================================================
// 任务中心UI管理器
// ===================================================================

/**
 * Manages the UI and state for the global asynchronous task center.
 * It handles task rendering, state updates, and user interactions like
 * opening/closing the panel and clearing completed tasks.
 */
class TaskCenterManager {
    constructor() {
        // --- 核心状态 ---
        this.tasks = []; // A history of all tasks started in this session.
        this.activePolls = new Map();
        this.heartbeatInterval = null;
        this.MINIMUM_TASK_DISPLAY_TIME_MS = 800;
        this.hasUnreadCompletedTasks = false;
        this.isAnimating = false;
        this.countdownTimer = null;
        // --- 核心DOM元素引用 ---
        this.trigger = document.getElementById('task-hub-trigger');
        this.panel = document.getElementById('task-hub-panel');
        this.countdownBar = document.getElementById('task-hub-countdown-bar'); 
        this.countdownRing = document.getElementById('task-hub-countdown-ring');
        this.indicator = document.getElementById('task-hub-indicator');
        this.clearBtn = document.getElementById('task-hub-clear-btn');
        this.taskListContainer = document.getElementById('task-list-container');
        this.emptyState = document.getElementById('task-list-empty');
    }
    // [THE FINAL, DEFINITIVE VERSION]
    init() {
        if (!this.trigger || !this.panel) {
            console.warn('Task Center UI core elements not found. Initialization skipped.');
            return;
        }
        
        // --- UI Event Listeners (Corrected and final) ---
        this.trigger.addEventListener('click', (event) => {
            event.stopPropagation();
            if (this.isAnimating) return;
            if (this.panel.classList.contains('hidden')) {
                this._handleUserInteraction(); 
                this.openPanel();
            } else {
                this.closePanel();
            }
        });
        
        document.addEventListener('click', (event) => {
            if (!this.panel.classList.contains('hidden') && !this.isAnimating && !this.panel.contains(event.target) && !this.trigger.contains(event.target)) {
                this.closePanel();
            }
        });
        this.trigger.addEventListener('mouseenter', this._stopCountdown.bind(this));
        this.panel.addEventListener('mouseenter', this._handleUserInteraction.bind(this));
        
        const handleMouseLeave = () => {
            if (!this.panel.classList.contains('hidden')) {
                this._startCountdown();
            }
        };
        this.panel.addEventListener('mouseleave', handleMouseLeave);
        this.trigger.addEventListener('mouseleave', handleMouseLeave);
        
        this.clearBtn?.addEventListener('click', this.clearCompletedTasks.bind(this));
        
        this.taskListContainer.addEventListener('click', (event) => {
            const toggleHeader = event.target.closest('[data-task-toggle]');
            if (!toggleHeader) return;
            this._handleUserInteraction();
            const taskItem = toggleHeader.closest('.task-list-item');
            const content = taskItem.querySelector('[data-task-content]');
            if (!content) return;
            const isCollapsed = content.classList.contains('collapsed');
            toggleHeader.classList.toggle('expanded', isCollapsed);
            if (isCollapsed) {
                content.classList.remove('collapsed');
                content.style.maxHeight = `${content.scrollHeight}px`;
                content.style.opacity = '1';
                content.addEventListener('transitionend', () => {
                   if (!content.classList.contains('collapsed')) content.style.maxHeight = 'none';
                }, { once: true });
            } else {
                content.style.maxHeight = `${content.scrollHeight}px`;
                requestAnimationFrame(() => {
                    content.style.maxHeight = '0px';
                    content.style.opacity = '0';
                    content.classList.add('collapsed');
                });
            }
        });
        this._render();
        
        // [CRITICAL FIX] IGNITION! START THE ENGINE!
        this._startHeartbeat();
        
        console.log('Task Center UI Initialized [Multi-Task Heartbeat Polling Architecture - IGNITED].');
    }
    async startTask(taskDefinition) {
        try {
            const initialTaskData = await taskDefinition.start();
            if (!initialTaskData || !initialTaskData.id) throw new Error("Task definition did not return a valid initial task object.");
            
            const newTask = {
                id: initialTaskData.id,
                definition: taskDefinition,
                data: initialTaskData,
                timestamp: new Date(),
                startTime: Date.now()
            };
            
            if (!initialTaskData.is_running) {
                console.log(`[TaskCenter] Task ${newTask.id} completed synchronously. Skipping poll.`);
                // We still show a brief toast for UX feedback.
                taskDefinition.renderToastNarrative(newTask.data, {}, toastManager);
                this.tasks.unshift(newTask);
                this._render();
                this._handleTaskCompletion(newTask);
                return; // IMPORTANT: Exit here to avoid adding it to the polling queue.
            }
            
            this.tasks.unshift(newTask);
            this.activePolls.set(newTask.id, newTask);
            
            this._render();
            this.openPanel();
            
            taskDefinition.renderToastNarrative(newTask.data, {}, toastManager);
            this._updateIndicatorState(); // [SAFETY] Update indicator immediately on new task.
        } catch (error) {
            console.error("Failed to start task:", error);
            toastManager.show(`任务启动失败: ${error.message}`, 'error');
        }
    }
    _startHeartbeat() {
        if (this.heartbeatInterval) return;
        this.heartbeatInterval = setInterval(this._tick.bind(this), 1500);
    }
    
    _stopHeartbeat() {
        if (this.heartbeatInterval) {
           clearInterval(this.heartbeatInterval);
           this.heartbeatInterval = null;
        }
    }
    async _tick() {
        if (this.activePolls.size === 0) {
            return;
        }
        // Iterate over a copy of keys to safely remove items during iteration.
        for (const taskId of [...this.activePolls.keys()]) {
            const task = this.activePolls.get(taskId);
            if (!task) continue; // Safety check
            try {
                const response = await task.definition.poll(taskId);
                if (!response.success || !response.data) throw new Error(response.message || "Polling failed");
                const oldData = { ...task.data };
                task.data = response.data;
                this._updateTaskItemInHistory(task.id, task.data); // [SAFETY] Keep history in sync.
                task.definition.renderToastNarrative(task.data, oldData, toastManager);
                 
                if (!task.data.is_running) {
                    this._handleTaskCompletion(task);
                }
            } catch (error) {
                console.error(`Polling for task ${taskId} failed:`, error);
                task.data.error = error.message;
                this._updateTaskItemInHistory(task.id, task.data);
                this._handleTaskCompletion(task);
            }
        }
    }
    _handleTaskCompletion(task) {
        this.activePolls.delete(task.id); 
        this._updateIndicatorState(); // [SAFETY] Update indicator as soon as a task is no longer active.
        
        const toastId = `task-${task.id}`;
        
        const finalize = async () => {
            await toastManager.dismiss(toastId, !task.data.error);
            this._updateTaskItemInDom(task);
            this.hasUnreadCompletedTasks = true;
            this._updateIndicatorState();
            if (task.data.error) {
                if (task.definition.onError) task.definition.onError(task.data);
            } else {
                if (task.definition.onSuccess) task.definition.onSuccess(task.data);
            }
        };
        const elapsedTime = Date.now() - task.startTime;
        const remainingTime = this.MINIMUM_TASK_DISPLAY_TIME_MS - elapsedTime;
        
        if (remainingTime > 0) {
            setTimeout(finalize, remainingTime);
        } else {
            finalize();
        }
    }
    // [REFACTORED for robustness]
    _updateIndicatorState() {
        const hasRunningTasks = this.activePolls.size > 0;
        const shouldBeVisible = hasRunningTasks || this.hasUnreadCompletedTasks;
        this.indicator.classList.toggle('hidden', !shouldBeVisible);
    }
    
    // [REFACTORED for robustness]
    clearCompletedTasks() {
        // Only keep tasks that are still in the active polling map.
        this.tasks = this.tasks.filter(task => this.activePolls.has(task.id));
        this.hasUnreadCompletedTasks = false;
        this._render();
    }
    
    // [NEW SAFETY METHOD]
    _updateTaskItemInHistory(taskId, newData) {
        const taskInHistory = this.tasks.find(t => t.id === taskId);
        if (taskInHistory) {
            taskInHistory.data = newData;
        }
    }

    // --- 渲染与DOM操作 ---
    _render() {
        this.taskListContainer.innerHTML = this.tasks.map(task => this._createTaskItemHtml(task)).join('');
        
        const hasTasks = this.tasks.length > 0;
        this.taskListContainer.classList.toggle('hidden', !hasTasks);
        this.emptyState.classList.toggle('hidden', hasTasks);
        
        this._updateIndicatorState();
    }
    _createTaskItemHtml(task) {
        // [MODIFIED] 将 this._formatTimeAgo 作为一个服务传递给渲染器
        const innerHtml = task.definition.renderTaskCenterItem(task.data, task.timestamp, this._formatTimeAgo);
        return `<div class="task-list-item" data-task-id="${task.id}">${innerHtml}</div>`;
    }
    _updateTaskItemInDom(task) {
        const item = this.taskListContainer.querySelector(`[data-task-id="${task.id}"]`);
        if (item) {
            // [MODIFIED] 将 this._formatTimeAgo 作为一个服务传递给渲染器
            item.innerHTML = task.definition.renderTaskCenterItem(task.data, task.timestamp, this._formatTimeAgo);
        }
    }

    // --- 核心面板开关逻辑 ---
    openPanel() {
        if (this.isAnimating || !this.panel.classList.contains('hidden')) return;

        this.isAnimating = true;
        this.panel.classList.remove('hidden');
        this.panel.classList.add('animate-panel-in');
        // 动画结束后，启动倒计时
        setTimeout(() => {
            this.panel.classList.remove('animate-panel-in');
            this.isAnimating = false;
            this._startCountdown(); // 启动倒计时
        }, 150);
    }
    
    closePanel() {
        if (this.isAnimating || this.panel.classList.contains('hidden')) return;
        
        this._stopCountdown(); // [修改] 关闭前立即停止倒计时
        this.isAnimating = true;
        this.panel.classList.add('animate-panel-out');
        setTimeout(() => {
            this.panel.classList.remove('animate-panel-out');
            this.panel.classList.add('hidden');
            this.isAnimating = false;
        }, 50);
    }
    
    // --- [新增] 倒计时管理方法 ---
    /**
     * 启动或重启倒计时和进度条动画
     * @private
     */
    _startCountdown() {
        this._stopCountdown(); // 先重置
        // 启动进度条动画
        this.countdownBar.classList.add('w-full', 'duration-[4950ms]');

        // 启动圆环动画 (通过可靠的JS强制重绘)
        this.countdownRing.style.transition = 'none'; // 1. 禁用动画
        this.countdownRing.style.strokeDashoffset = '72.26'; // 2. 立即重置
        void this.countdownRing.offsetHeight; // 3. 强制浏览器重排
        this.countdownRing.style.transition = 'stroke-dashoffset 4.95s linear'; // 4. 重新启用动画
        this.countdownRing.style.strokeDashoffset = '0'; // 5. 设置目标值，开始动画

        // 启动关闭计时器
        this.countdownTimer = setTimeout(() => {
            this.closePanel();
        }, 4950);
    }
    /**
     * 停止倒计时并重置进度条
     * @private
     */
    _stopCountdown() {
        if (this.countdownTimer) {
            clearTimeout(this.countdownTimer);
            this.countdownTimer = null;
        }
        // 重置进度条的视觉状态
        this.countdownBar.classList.remove('w-full');

        this.countdownRing.style.transition = 'none';
        this.countdownRing.style.strokeDashoffset = '72.26';
    }

    // [NEW] A central handler for any action that confirms the user has seen the panel.
    _handleUserInteraction() {
        // 1. Stop the auto-close countdown because the user is now interacting.
        this._stopCountdown();
        // 2. If there were unread tasks, mark them as read *now*.
        if (this.hasUnreadCompletedTasks) {
            this.hasUnreadCompletedTasks = false;
            this._updateIndicatorState(); // The indicator light turns off at this moment.
        }
    }

    _formatTimeAgo(date) {
        if (!date) return '';
        const seconds = Math.floor((new Date() - new Date(date)) / 1000);
        if (seconds < 2) return "刚刚";
        if (seconds < 60) return `${seconds}秒前`;
        const minutes = Math.floor(seconds / 60);
        if (minutes < 60) return `${minutes}分钟前`;
        const hours = Math.floor(minutes / 60);
        if (hours < 24) return `${hours}小时前`;
        const days = Math.floor(hours / 24);
        return `${days}天前`;
    }
}

// ===================================================================
// [NEW] Toast 通知管理器
// ===================================================================
class ToastManager {
    constructor() {
        this.container = document.getElementById('toast-container');
        if (!this.container) {
            this.container = document.createElement('div');
            this.container.id = 'toast-container';
            this.container.className = 'fixed bottom-4 right-4 z-[100] w-full max-w-sm space-y-3'; // 宽度可稍大
            document.body.appendChild(this.container);
        }
        this.activeToasts = new Map(); // [NEW] 用于跟踪可更新的进度Toast
    }
    /**
     * 显示一个 Toast 通知
     * @param {string} message - The message to display.
     * @param {string} [type='info'] - 'info', 'success', or 'error'.
     * @param {number} [duration=4000] - Duration in milliseconds.
     */
    show(message, type = 'info', duration = 4000) {
        const toastElement = this._createToastHtml(message, type);
        this.container.appendChild(toastElement);
        // 强制重绘以触发入场动画
        requestAnimationFrame(() => {
            toastElement.classList.remove('opacity-0', 'translate-y-2');
            toastElement.classList.add('opacity-100', 'translate-y-0');
        });
        // 设置定时器以移除 Toast
        setTimeout(() => {
            toastElement.classList.remove('opacity-100', 'translate-y-0');
            toastElement.classList.add('opacity-0', 'translate-y-2');
            // 在动画结束后从 DOM 中移除
            toastElement.addEventListener('transitionend', () => toastElement.remove(), { once: true });
        }, duration);
    }

    // [NEW] 创建或更新一个带进度条的Toast
    showProgressToast(toastId, title, message, progress) {
        if (this.activeToasts.has(toastId)) {
            // --- 更新现有Toast ---
            const toastElement = this.activeToasts.get(toastId);
            const messageEl = toastElement.querySelector('.toast-message');
            const progressBar = toastElement.querySelector('.toast-progress-bar');
            
            messageEl.textContent = `${message} - ${Math.round(progress)}%`;
            anime({
                targets: progressBar,
                width: `${progress}%`,
                duration: 400,
                easing: 'easeOutQuad'
            });
        } else {
            // --- 创建新的Toast ---
            const toastElement = this._createProgressToastHtml(toastId, title, message, progress);
            this.container.appendChild(toastElement);
            this.activeToasts.set(toastId, toastElement);
            requestAnimationFrame(() => {
                toastElement.classList.remove('opacity-0', 'translate-x-full');
                toastElement.classList.add('opacity-100', 'translate-x-0');
            });
        }
    }
    // [NEW] 移除一个进度Toast
    dismiss(toastId, success = null) {
        return new Promise((resolve) => {
            if (!this.activeToasts.has(toastId)) {
                resolve();
                return;
            }
            const toastElement = this.activeToasts.get(toastId);
            const performFadeOut = () => {
                toastElement.classList.remove('opacity-100', 'translate-x-0');
                toastElement.classList.add('opacity-0', 'translate-x-full');
                toastElement.addEventListener('transitionend', () => {
                    toastElement.remove();
                    this.activeToasts.delete(toastId);
                    resolve(); // Resolve the promise ONLY when the element is fully gone.
                }, { once: true });
            };
            if (success === null) { // Immediate dismissal
                performFadeOut();
            } else { // Graceful, animated dismissal
                const iconContainer = toastElement.querySelector('.toast-icon');
                const messageEl = toastElement.querySelector('.toast-message');
                if (success) {
                    const progressBar = toastElement.querySelector('.toast-progress-bar');
                    messageEl.textContent = '已完成';
                    anime({
                        targets: progressBar,
                        width: '100%',
                        duration: 300,
                        easing: 'easeOutQuad',
                        complete: () => {
                            iconContainer.innerHTML = `<i class="fas fa-check-circle text-white"></i>`;
                            iconContainer.className = `toast-icon bg-green-500`;
                            setTimeout(performFadeOut, 900);
                        }
                    });
                } else { // Failure
                    iconContainer.innerHTML = `<i class="fas fa-times-circle text-white"></i>`;
                    iconContainer.className = `toast-icon bg-red-500`;
                    messageEl.textContent = '失败';
                    setTimeout(performFadeOut, 1200);
                }
            }
        });
    }

    _createToastHtml(message, type) {
        const icons = {
            info: { class: 'bg-blue-500', icon: 'fa-info-circle' },
            success: { class: 'bg-green-500', icon: 'fa-check-circle' },
            error: { class: 'bg-red-500', icon: 'fa-exclamation-triangle' }
        };
        const typeInfo = icons[type] || icons.info;
        const toast = document.createElement('div');
        toast.className = 'toast-item opacity-0 translate-y-2 transition-all duration-300 ease-out'; // 初始状态为动画准备
        toast.innerHTML = `
            <div class="toast-icon ${typeInfo.class}">
                <i class="fas ${typeInfo.icon}"></i>
            </div>
            <div class="toast-content">
                <p class="toast-title">${this._capitalizeFirstLetter(type)}</p>
                <p class="toast-message">${message}</p>
            </div>
        `;
        return toast;
    }

    // [NEW] 创建带进度条Toast的HTML结构
    _createProgressToastHtml(toastId, title, message, progress) {
        const toast = document.createElement('div');
        toast.className = 'toast-item opacity-0 translate-x-full transition-all duration-300 ease-out';
        toast.dataset.toastId = toastId;
        toast.innerHTML = `
            <div class="toast-icon bg-blue-500">
                <i class="fas fa-spinner animate-spin"></i>
            </div>
            <div class="toast-content">
                <p class="toast-title">${title}</p>
                <p class="toast-message">${message} - ${Math.round(progress)}%</p>
                <div class="w-full bg-slate-200 dark:bg-zinc-700 rounded-full h-1 mt-1.5 overflow-hidden">
                    <div class="toast-progress-bar bg-blue-500 h-1 rounded-full" style="width: ${progress}%;"></div>
                </div>
            </div>
        `;
        return toast;
    }

    _capitalizeFirstLetter(string) {
        return string.charAt(0).toUpperCase() + string.slice(1);
    }
}


export const taskCenterManager = new TaskCenterManager();
export const toastManager = new ToastManager();

// [OPTIONAL] 为了向后兼容或简化调用，可以导出一个独立的 showToast 函数
export const showToast = (message, type, duration) => toastManager.show(message, type, duration);