'use strict';

const express = require('express');

// In-memory ring buffer for log entries
const MAX_ENTRIES = 1000;
const logEntries = [];
let logId = 0;

// Monkey-patch console to capture output
const origLog = console.log;
const origError = console.error;
const origWarn = console.warn;

function captureLog(level, args) {
	const text = args.map(a => {
		if (typeof a === 'string') return a;
		try { return JSON.stringify(a); } catch(e) { return String(a); }
	}).join(' ');

	logEntries.push({
		id: ++logId,
		level,
		text,
		timestamp: Date.now(),
	});
	if (logEntries.length > MAX_ENTRIES) logEntries.splice(0, logEntries.length - MAX_ENTRIES);
}

console.log = function (...args) {
	captureLog('log', args);
	origLog.apply(console, args);
};

console.error = function (...args) {
	captureLog('error', args);
	origError.apply(console, args);
};

console.warn = function (...args) {
	captureLog('warn', args);
	origWarn.apply(console, args);
};

function createRouter() {
	const router = express.Router();

	router.get('/api/logs', (req, res) => {
		try {
			const since = parseInt(req.query.since) || 0;
			const level = req.query.level; // comma-separated: "log,error,warn"
			const allowedLevels = level ? new Set(level.split(',')) : null;

			let filtered = since ? logEntries.filter(e => e.id > since) : logEntries.slice(-200);
			if (allowedLevels) {
				filtered = filtered.filter(e => allowedLevels.has(e.level));
			}

			res.json({ entries: filtered, lastId: logId });
		} catch (error) {
			res.status(500).json({ error: error.message });
		}
	});

	return router;
}

const webUI = {
	tabId: 'logs',
	tabLabel: 'Logs',
	tabOrder: 25,
	html: `
		<div id="logArea">
			<div class="log-controls">
				<label class="log-filter"><input type="checkbox" checked onchange="updateLogFilter()" id="logShowLog"> Log</label>
				<label class="log-filter"><input type="checkbox" checked onchange="updateLogFilter()" id="logShowError"> Error</label>
				<label class="log-filter"><input type="checkbox" checked onchange="updateLogFilter()" id="logShowWarn"> Warn</label>
				<input type="text" id="logSearch" placeholder="Search logs..." oninput="rerenderLogs()" style="flex:1;padding:8px 12px;border:1px solid #374151;border-radius:6px;background:#111827;color:#e5e7eb;font-size:.85em">
			</div>
			<div class="log-feed" id="logFeed">
				<div style="padding:20px;color:#6b7280;text-align:center">Loading logs...</div>
			</div>
		</div>
	`,
	css: `
		#logArea{display:flex;flex-direction:column;height:calc(100vh - 140px)}
		.log-controls{display:flex;gap:10px;align-items:center;margin-bottom:8px;flex-wrap:wrap}
		.log-filter{font-size:.85em;color:#9ca3af;display:flex;align-items:center;gap:4px;cursor:pointer}
		.log-filter input[type=checkbox]{accent-color:#2563eb}
		.log-feed{flex:1;overflow-y:auto;padding:8px;background:#0f172a;border:1px solid #374151;border-radius:8px;font-family:'Consolas','Monaco',monospace;font-size:.8em;line-height:1.5}
		.log-line{padding:2px 4px;word-wrap:break-word;border-bottom:1px solid #1e293b}
		.log-line .log-time{color:#4b5563;margin-right:6px;font-size:.85em}
		.log-line .log-level{font-weight:700;margin-right:6px;font-size:.8em;padding:1px 5px;border-radius:3px}
		.log-line .log-level.log{color:#60a5fa;background:rgba(96,165,250,.1)}
		.log-line .log-level.error{color:#ef4444;background:rgba(239,68,68,.1)}
		.log-line .log-level.warn{color:#f59e0b;background:rgba(245,158,11,.1)}
		.log-line.level-error{background:rgba(239,68,68,.05)}
		.log-line.level-warn{background:rgba(245,158,11,.05)}
	`,
	onTabActive: 'onLogTabActive',
	js: `
let logLastId=0, logInterval=null, logAutoScroll=true, allLogEntries=[];

function onLogTabActive() {
	loadLogs();
	if (!logInterval) logInterval = setInterval(() => { if (currentTab === 'logs') pollLogs(); }, 2000);
}

function getLogLevels() {
	const levels = [];
	if (document.getElementById('logShowLog').checked) levels.push('log');
	if (document.getElementById('logShowError').checked) levels.push('error');
	if (document.getElementById('logShowWarn').checked) levels.push('warn');
	return levels;
}

function updateLogFilter() { rerenderLogs(); }

async function loadLogs() {
	try {
		const r = await fetch('/api/logs');
		if (!r.ok) return;
		const d = await r.json();
		logLastId = d.lastId || 0;
		allLogEntries = d.entries || [];
		rerenderLogs();
	} catch(e) {}
}

async function pollLogs() {
	try {
		const r = await fetch('/api/logs?since=' + logLastId);
		if (!r.ok) return;
		const d = await r.json();
		if (d.entries && d.entries.length > 0) {
			logLastId = d.lastId || logLastId;
			allLogEntries = allLogEntries.concat(d.entries);
			if (allLogEntries.length > 2000) allLogEntries = allLogEntries.slice(-1500);
			appendLogEntries(d.entries);
		}
	} catch(e) {}
}

function formatLogTime(ts) {
	const d = new Date(ts);
	return d.toLocaleTimeString([], {hour:'2-digit',minute:'2-digit',second:'2-digit'});
}

function renderLogLine(entry) {
	return '<div class="log-line level-' + entry.level + '">' +
		'<span class="log-time">' + formatLogTime(entry.timestamp) + '</span>' +
		'<span class="log-level ' + entry.level + '">' + entry.level.toUpperCase() + '</span>' +
		escHtml(entry.text) +
	'</div>';
}

function matchesLogFilter(entry) {
	const levels = getLogLevels();
	if (!levels.includes(entry.level)) return false;
	const q = (document.getElementById('logSearch').value || '').toLowerCase();
	if (q && !entry.text.toLowerCase().includes(q)) return false;
	return true;
}

function rerenderLogs() {
	const feed = document.getElementById('logFeed');
	const filtered = allLogEntries.filter(matchesLogFilter);
	if (filtered.length === 0) {
		feed.innerHTML = '<div style="padding:20px;color:#6b7280;text-align:center">No log entries</div>';
		return;
	}
	feed.innerHTML = filtered.map(renderLogLine).join('');
	if (logAutoScroll) feed.scrollTop = feed.scrollHeight;
}

function appendLogEntries(entries) {
	const feed = document.getElementById('logFeed');
	const placeholder = feed.querySelector('div[style]');
	if (placeholder && feed.children.length === 1 && placeholder.textContent.includes('No log')) {
		feed.innerHTML = '';
	}
	const filtered = entries.filter(matchesLogFilter);
	for (const entry of filtered) {
		feed.insertAdjacentHTML('beforeend', renderLogLine(entry));
	}
	while (feed.children.length > 1500) feed.removeChild(feed.firstChild);
	if (logAutoScroll) feed.scrollTop = feed.scrollHeight;
}

document.getElementById('logFeed').addEventListener('scroll', function() {
	logAutoScroll = this.scrollTop + this.clientHeight >= this.scrollHeight - 30;
});
	`,
};

module.exports = { name: 'Logs', createRouter, webUI };
