'use strict';

const express = require('express');
const { CJbot } = require('../model/minecraft');

// In-memory ring buffer for chat messages
const MAX_MESSAGES = 500;
const messages = [];
let messageId = 0;

function addMessage(type, from, text, botName) {
	messages.push({
		id: ++messageId,
		type,       // 'chat', 'whisper', 'system', 'bot'
		from,
		text,
		botName,
		timestamp: Date.now(),
	});
	if (messages.length > MAX_MESSAGES) messages.splice(0, messages.length - MAX_MESSAGES);
}

// Hook into all bots' chat events (called once per bot connection)
const hookedBots = new Set();

function hookBot(bot) {
	const name = bot.name;
	if (hookedBots.has(name)) return;
	hookedBots.add(name);

	// Re-hook on each spawn (reconnection creates a new mineflayer bot)
	const attach = () => {
		if (!bot.bot) return;
		bot.bot.on('chat', (from, message) => {
			addMessage('chat', from, message, name);
		});
		bot.bot.on('whisper', (from, message) => {
			addMessage('whisper', from, message, name);
		});
		bot.bot.on('message', (jsonMsg, position) => {
			if (position === 'game_info') return; // skip action bar
			const text = jsonMsg.toString();
			// Skip empty or already-captured chat/whisper
			if (!text || text.startsWith('<')) return;
			addMessage('system', null, text, name);
		});
	};

	// If the bot is already connected, attach now
	if (bot.bot) attach();

	// Also attach on every future spawn
	const origConnect = bot.connect.bind(bot);
	bot.connect = async function (...args) {
		const result = await origConnect(...args);
		attach();
		return result;
	};
}

// Periodically check for new bots to hook
setInterval(() => {
	for (const [name, bot] of Object.entries(CJbot.bots)) {
		hookBot(bot);
	}
}, 2000);

// Also hook any bots that exist right now
for (const [name, bot] of Object.entries(CJbot.bots)) {
	hookBot(bot);
}

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

	// Get messages, optionally filtering by ?since=<id> for polling
	router.get('/api/chat/messages', (req, res) => {
		try {
			const since = parseInt(req.query.since) || 0;
			const filtered = since ? messages.filter(m => m.id > since) : messages.slice(-100);
			res.json({ messages: filtered, lastId: messageId });
		} catch (error) {
			console.error('API Error /api/chat/messages:', error);
			res.status(500).json({ error: error.message });
		}
	});

	// Send a chat message as a bot
	router.post('/api/chat/send', async (req, res) => {
		try {
			const { botName, message, whisperTo } = req.body;
			if (!message) return res.status(400).json({ error: 'Missing message' });

			// Find a bot to send from
			let bot = null;
			if (botName && CJbot.bots[botName]) {
				bot = CJbot.bots[botName];
			} else {
				// Use first connected bot
				for (const b of Object.values(CJbot.bots)) {
					if (b.isReady) { bot = b; break; }
				}
			}

			if (!bot || !bot.isReady) {
				return res.status(503).json({ error: 'No connected bot available' });
			}

			if (whisperTo) {
				await bot.whisper(whisperTo, message);
				addMessage('bot', bot.bot.entity.username, `/msg ${whisperTo} ${message}`, bot.name);
			} else {
				await bot.say(message);
				addMessage('bot', bot.bot.entity.username, message, bot.name);
			}

			res.json({ status: 'sent' });
		} catch (error) {
			console.error('API Error /api/chat/send:', error);
			res.status(500).json({ error: error.message });
		}
	});

	return router;
}

const webUI = {
	tabId: 'chat',
	tabLabel: 'Chat',
	tabOrder: 5,
	html: `
		<div id="chatArea">
			<div class="chat-messages" id="chatMessages">
				<div style="padding:20px;color:#6b7280;text-align:center">Loading chat...</div>
			</div>
			<div class="chat-input-area">
				<select id="chatBot" style="padding:8px;border:1px solid #374151;border-radius:6px;background:#111827;color:#e5e7eb;font-size:.85em">
					<option value="">Any bot</option>
				</select>
				<input type="text" id="chatWhisper" placeholder="Whisper to (optional)" style="width:120px;padding:8px;border:1px solid #374151;border-radius:6px;background:#111827;color:#e5e7eb;font-size:.85em">
				<input type="text" id="chatInput" placeholder="Type a message..." autocomplete="off" style="flex:1;padding:8px 12px;border:1px solid #374151;border-radius:6px;background:#111827;color:#e5e7eb;font-size:.9em">
				<button id="chatSendBtn" style="background:#2563eb;color:#fff;border:none;padding:8px 16px;border-radius:6px;cursor:pointer;font-size:.85em">Send</button>
			</div>
		</div>
	`,
	css: `
		#chatArea{display:flex;flex-direction:column;height:calc(100vh - 140px)}
		.chat-messages{flex:1;overflow-y:auto;padding:12px;background:#0f172a;border:1px solid #374151;border-radius:8px;margin-bottom:12px;font-family:'Consolas','Monaco',monospace;font-size:.85em;line-height:1.6}
		.chat-msg{padding:2px 0;word-wrap:break-word}
		.chat-msg .chat-time{color:#4b5563;font-size:.8em;margin-right:6px}
		.chat-msg .chat-from{font-weight:600}
		.chat-msg.type-chat .chat-from{color:#60a5fa}
		.chat-msg.type-whisper .chat-from{color:#a78bfa}
		.chat-msg.type-whisper{background:rgba(167,139,250,.08);padding:2px 4px;border-radius:3px}
		.chat-msg.type-system{color:#6b7280;font-style:italic}
		.chat-msg.type-bot .chat-from{color:#f59e0b}
		.chat-input-area{display:flex;gap:8px;align-items:center}
		.chat-filter-bar{display:flex;gap:8px;align-items:center;margin-bottom:8px}
		.chat-filter-bar input{padding:8px 12px;border:1px solid #374151;border-radius:6px;background:#111827;color:#e5e7eb;font-size:.85em;flex:1}
		.chat-filter-bar label{font-size:.8em;color:#9ca3af;display:flex;align-items:center;gap:4px;cursor:pointer}
		.chat-filter-bar label input[type=checkbox]{accent-color:#2563eb}
	`,
	onTabActive: 'onChatTabActive',
	js: `
let chatLastId=0, chatInterval=null, chatAutoScroll=true, chatFilter='';
let chatShowTypes={chat:true,whisper:true,system:true,bot:true};

function onChatTabActive() {
	loadChatMessages();
	populateBotSelect();
	if (!chatInterval) chatInterval = setInterval(() => { if (currentTab === 'chat') pollChat(); }, 1500);
}

async function loadChatMessages() {
	try {
		const r = await fetch('/api/chat/messages');
		if (!r.ok) return;
		const d = await r.json();
		chatLastId = d.lastId || 0;
		renderChatMessages(d.messages || []);
	} catch(e) {}
}

async function pollChat() {
	try {
		const r = await fetch('/api/chat/messages?since=' + chatLastId);
		if (!r.ok) return;
		const d = await r.json();
		if (d.messages && d.messages.length > 0) {
			chatLastId = d.lastId || chatLastId;
			appendChatMessages(d.messages);
		}
	} catch(e) {}
}

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

function renderChatLine(msg) {
	const time = '<span class="chat-time">' + formatChatTime(msg.timestamp) + '</span>';
	if (msg.type === 'system') {
		return '<div class="chat-msg type-system">' + time + escHtml(msg.text) + '</div>';
	}
	const label = msg.type === 'whisper' ? ' whispers: ' : ': ';
	return '<div class="chat-msg type-' + msg.type + '">' +
		time +
		'<span class="chat-from">' + escHtml(msg.from || '???') + '</span>' +
		label + escHtml(msg.text) +
	'</div>';
}

function matchesFilter(msg) {
	if (!chatShowTypes[msg.type]) return false;
	if (!chatFilter) return true;
	const q = chatFilter.toLowerCase();
	return (msg.from && msg.from.toLowerCase().includes(q)) ||
		(msg.text && msg.text.toLowerCase().includes(q));
}

function renderChatMessages(msgs) {
	const container = document.getElementById('chatMessages');
	const filtered = msgs.filter(matchesFilter);
	if (filtered.length === 0) {
		container.innerHTML = '<div style="padding:20px;color:#6b7280;text-align:center">No messages yet</div>';
		return;
	}
	container.innerHTML = filtered.map(renderChatLine).join('');
	if (chatAutoScroll) container.scrollTop = container.scrollHeight;
}

function appendChatMessages(msgs) {
	const container = document.getElementById('chatMessages');
	// Remove placeholder if present
	const placeholder = container.querySelector('div[style]');
	if (placeholder && container.children.length === 1 && placeholder.textContent.includes('No messages')) {
		container.innerHTML = '';
	}
	const filtered = msgs.filter(matchesFilter);
	for (const msg of filtered) {
		container.insertAdjacentHTML('beforeend', renderChatLine(msg));
	}
	// Trim old messages from DOM
	while (container.children.length > 500) container.removeChild(container.firstChild);
	if (chatAutoScroll) container.scrollTop = container.scrollHeight;
}

async function populateBotSelect() {
	try {
		const r = await fetch('/api/bots');
		if (!r.ok) return;
		const d = await r.json();
		const sel = document.getElementById('chatBot');
		const current = sel.value;
		sel.innerHTML = '<option value="">Any bot</option>' +
			Object.entries(d.bots || {}).filter(([,b]) => b.connected).map(([name]) =>
				'<option value="' + escHtml(name) + '">' + escHtml(name) + '</option>'
			).join('');
		sel.value = current;
	} catch(e) {}
}

async function sendChatMessage() {
	const input = document.getElementById('chatInput');
	const message = input.value.trim();
	if (!message) return;
	const botName = document.getElementById('chatBot').value || undefined;
	const whisperTo = document.getElementById('chatWhisper').value.trim() || undefined;
	try {
		const r = await fetch('/api/chat/send', {
			method: 'POST',
			headers: {'Content-Type': 'application/json'},
			body: JSON.stringify({ botName, message, whisperTo })
		});
		if (r.ok) {
			input.value = '';
			setTimeout(pollChat, 300);
		} else {
			const d = await r.json();
			showToast(d.error || 'Failed to send', 'error');
		}
	} catch(e) { showToast('Network error', 'error'); }
}

document.getElementById('chatInput').addEventListener('keydown', e => {
	if (e.key === 'Enter') { e.preventDefault(); sendChatMessage(); }
});
document.getElementById('chatSendBtn').addEventListener('click', sendChatMessage);

// Auto-scroll toggle: disable if user scrolls up, re-enable at bottom
document.getElementById('chatMessages').addEventListener('scroll', function() {
	chatAutoScroll = this.scrollTop + this.clientHeight >= this.scrollHeight - 30;
});
	`,
};

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