// SignalR Task Log Connection Manager - Reusable client for task log updates
class TaskLogConnectionManager {
    constructor(serverUrl, taskId) {
        this.serverUrl = serverUrl;
        this.taskId = taskId;
        this.connection = null;
        this.hubProxy = null;
        this.isConnecting = false;
        this.reconnectAttempts = 0;
        this.maxReconnectAttempts = 5;
        this.reconnectDelay = 5000; // 5 seconds
        this.connectionState = {
            CONNECTING: 0,
            CONNECTED: 1,
            RECONNECTING: 2,
            DISCONNECTED: 4
        };
    }

    async connect() {
        if (this.isConnecting || (this.connection && this.connection.state === this.connectionState.CONNECTED)) {
            return;
        }

        this.isConnecting = true;
        console.log("Initializing SignalR connection to task log hub");

        try {
            const chatServerUrl = this.serverUrl + "CentralServerWebservices/";
            const chatUrl = chatServerUrl + "signalr";

            // Create connection with proper configuration
            this.connection = $.hubConnection(chatUrl, {
                useDefaultPath: false,
                logging: false, // Set to true for debugging
                transport: ['webSockets', 'serverSentEvents', 'longPolling'] // Fallback transports
            });

            // Create hub proxy
            this.hubProxy = this.connection.createHubProxy('TaskLogHub');

            // Set up event handlers
            this.setupEventHandlers();

            // Start connection with retry logic
            await this.startConnection();

        } catch (error) {
            console.error("Failed to initialize SignalR connection:", error);
            this.isConnecting = false;
            this.scheduleReconnect();
        }
    }

    setupEventHandlers() {
        // Handle incoming log messages
        this.hubProxy.on("TaskLogUpdated", (logLine) => {
            this.handleLogUpdate(logLine);
        });

        // Connection state change handlers
        this.connection.stateChanged((change) => {
            console.log(`SignalR connection state changed: ${this.getStateString(change.oldState)} -> ${this.getStateString(change.newState)}`);

            if (change.newState === this.connectionState.DISCONNECTED) {
                this.handleDisconnection();
            }
        });

        // Connection slow handler
        this.connection.connectionSlow(() => {
            console.warn("SignalR connection is slow");
        });

        // Error handler
        this.connection.error((error) => {
            console.error("SignalR connection error:", error);
        });

        // Reconnecting handler
        this.connection.reconnecting(() => {
            console.log("SignalR attempting to reconnect...");
        });

        // Reconnected handler
        this.connection.reconnected(() => {
            console.log("SignalR reconnected successfully");
            this.reconnectAttempts = 0;
            this.joinTaskGroup();
        });
    }

    async startConnection() {
        return new Promise((resolve, reject) => {
            this.connection.start()
                .done(() => {
                    console.log("SignalR connected successfully");
                    this.isConnecting = false;
                    this.reconnectAttempts = 0;
                    this.joinTaskGroup();
                    resolve();
                })
                .fail((error) => {
                    console.error("Failed to connect to SignalR hub:", error);
                    this.isConnecting = false;
                    reject(error);
                });
        });
    }

    joinTaskGroup() {
        if (this.hubProxy && this.connection.state === this.connectionState.CONNECTED) {
            this.hubProxy.invoke("AddToTaskGroup", this.taskId)
                .done(() => {
                    console.log(`Successfully joined task group for task ID: ${this.taskId}`);
                })
                .fail((error) => {
                    console.error("Failed to join task group:", error);
                });
        }
    }

    handleLogUpdate(logLine) {
        try {
            // Sanitize the log line to prevent XSS
            const sanitizedLogLine = this.sanitizeHtml(logLine);

            let taskLogElement = document.getElementById("task-logs");
            if (!taskLogElement) {
                const noLogsMessage = document.getElementById("no-logs-message");
                if (noLogsMessage) {
                    noLogsMessage.outerHTML = '<div id="task-logs"></div>';
                    taskLogElement = document.getElementById("task-logs");
                }
            }

            if (taskLogElement) {
                // Use safer DOM manipulation
                const logEntry = document.createElement('div');
                logEntry.innerHTML = sanitizedLogLine;
                taskLogElement.appendChild(logEntry);

                // Auto-scroll to bottom
                taskLogElement.scrollTop = taskLogElement.scrollHeight;

                // Limit the number of log entries to prevent memory issues
                this.limitLogEntries(taskLogElement, 1000);
            }
        } catch (error) {
            console.error("Error handling log update:", error);
        }
    }

    sanitizeHtml(html) {
        const temp = document.createElement('div');
        temp.textContent = html;
        return temp.innerHTML;
    }

    limitLogEntries(container, maxEntries) {
        const children = container.children;
        if (children.length > maxEntries) {
            const entriesToRemove = children.length - maxEntries;
            for (let i = 0; i < entriesToRemove; i++) {
                container.removeChild(children[0]);
            }
        }
    }

    handleDisconnection() {
        if (this.reconnectAttempts < this.maxReconnectAttempts) {
            this.scheduleReconnect();
        } else {
            console.error("Maximum reconnection attempts reached. Connection abandoned.");
            this.showConnectionError();
        }
    }

    scheduleReconnect() {
        if (this.reconnectAttempts >= this.maxReconnectAttempts) {
            return;
        }

        this.reconnectAttempts++;
        const delay = this.reconnectDelay * Math.pow(2, this.reconnectAttempts - 1); // Exponential backoff

        console.log(`Scheduling reconnection attempt ${this.reconnectAttempts} in ${delay}ms`);

        setTimeout(() => {
            if (this.connection.state === this.connectionState.DISCONNECTED) {
                this.connect();
            }
        }, delay);
    }

    showConnectionError() {
        // Show user-friendly error message
        const errorDiv = document.createElement('div');
        errorDiv.className = 'signalr-error-message';
        errorDiv.innerHTML = `
            <div style="background-color: #f8d7da; color: #721c24; padding: 10px; border: 1px solid #f5c6cb; border-radius: 4px; margin: 10px 0;">
                <strong>Connection Lost:</strong> Real-time log updates are currently unavailable.
                <button onclick="location.reload()" style="margin-left: 10px;">Refresh Page</button>
            </div>
        `;

        const logSection = document.querySelector('.group:last-child');
        if (logSection) {
            logSection.insertBefore(errorDiv, logSection.firstChild);
        }
    }

    getStateString(state) {
        switch (state) {
            case this.connectionState.CONNECTING: return "Connecting";
            case this.connectionState.CONNECTED: return "Connected";
            case this.connectionState.RECONNECTING: return "Reconnecting";
            case this.connectionState.DISCONNECTED: return "Disconnected";
            default: return "Unknown";
        }
    }

    disconnect() {
        if (this.connection) {
            console.log("Disconnecting from SignalR hub");
            this.connection.stop();
            this.connection = null;
            this.hubProxy = null;
        }
    }
}

// Simple connection manager for basic SignalR functionality (legacy support)
class SimpleSignalRConnection {
    constructor(serverUrl, taskId) {
        this.serverUrl = serverUrl;
        this.taskId = taskId;
        this.connection = null;
        this.hubProxy = null;
    }

    connect() {
        const chatServerUrl = this.serverUrl + "CentralServerWebservices/";
        const chatUrl = chatServerUrl + "signalr";

        console.log("connecting to " + chatUrl);
        this.connection = $.hubConnection(chatUrl, {
            useDefaultPath: false
        });
        this.hubProxy = this.connection.createHubProxy('TaskLogHub');

        // Set up log update handler
        this.hubProxy.on("TaskLogUpdated", (logLine) => {
            this.handleLogUpdate(logLine);
        });

        // Start connection
        this.connection.start().done(() => {
            this.hubProxy.invoke("AddToTaskGroup", this.taskId);
        }).fail(() => {
            console.log("failed in connecting to the signalr server");
        });
    }

    handleLogUpdate(logLine) {
        let taskLog = document.getElementById("task-logs");
        if (!taskLog) {
            const nolosgMessage = document.getElementById("no-logs-message");

            if (nolosgMessage) {
                $(nolosgMessage).replaceWith('<div id="task-logs"></div>');
                taskLog = document.getElementById("task-logs");
            }
        }

        if (taskLog) {
            $(taskLog).append(logLine);
            $(taskLog).append('<br />');
            taskLog.scrollTop = taskLog.scrollHeight;
        }
    }

    disconnect() {
        if (this.connection) {
            this.connection.stop();
            this.connection = null;
            this.hubProxy = null;
        }
    }
}

// Global functions for backward compatibility
let globalSignalRConnection = null;

function Connect(serverUrl, taskId) {
    if (globalSignalRConnection) {
        globalSignalRConnection.disconnect();
    }
    globalSignalRConnection = new SimpleSignalRConnection(serverUrl, taskId);
    globalSignalRConnection.connect();
}

// Cleanup function for global connection
function disconnectSignalR() {
    if (globalSignalRConnection) {
        globalSignalRConnection.disconnect();
        globalSignalRConnection = null;
    }
}