import { Injectable, OnModuleDestroy } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import {
	BaseMatrixService,
	MatrixBotConfig,
	MatrixRoomEvent,
	KeywordCommandDetector,
	COMMON_KEYWORDS,
} from '@manacore/matrix-bot-common';
import { ClockService, Timer } from '../clock/clock.service';
import {
	TranscriptionService,
	SessionService,
	CreditService,
	I18nService,
	Language,
	LANGUAGE_NAMES,
	LOGIN_MESSAGES,
} from '@manacore/bot-services';
import { HELP_TEXT, WELCOME_TEXT } from '../config/configuration';

/**
 * Tracking info for live timer updates
 */
interface TimerMessageTracker {
	timerId: string;
	roomId: string;
	eventId: string;
	userId: string;
	token: string;
	durationSeconds: number;
	label: string | null;
	startedAt: Date;
}

/**
 * Room topic tracking for timer display
 */
interface RoomTopicTracker {
	originalTopic: string;
	timerId: string;
}

@Injectable()
export class MatrixService extends BaseMatrixService implements OnModuleDestroy {
	// Demo token for development (TODO: implement proper auth)
	private readonly demoToken = process.env.CLOCK_API_TOKEN || '';

	// Track active timer messages for live updates
	private readonly activeTimerMessages = new Map<string, TimerMessageTracker>();
	private timerUpdateInterval: NodeJS.Timeout | null = null;
	private readonly UPDATE_INTERVAL_MS = 10000; // Update every 10 seconds

	// Track original room topics for restoration when timer ends
	private readonly originalRoomTopics = new Map<string, RoomTopicTracker>();

	// Note: We override COMMON_KEYWORDS' cancel->cancel with stop->stop for this bot
	private readonly keywordDetector = new KeywordCommandDetector([
		{ keywords: ['hilfe', 'help', 'befehle', 'commands'], command: 'help' },
		{ keywords: ['status', 'timer status', 'laufend'], command: 'status' },
		{ keywords: ['stop', 'stopp', 'pause', 'anhalten'], command: 'stop' },
		{ keywords: ['weiter', 'resume', 'fortsetzen'], command: 'resume' },
		{ keywords: ['zeit', 'time', 'uhrzeit', 'wie spat'], command: 'time' },
	]);

	constructor(
		configService: ConfigService,
		private clockService: ClockService,
		private transcriptionService: TranscriptionService,
		private sessionService: SessionService,
		private creditService: CreditService,
		private i18nService: I18nService
	) {
		super(configService);
		this.startTimerUpdateLoop();
	}

	/**
	 * Cleanup on module destroy
	 */
	async onModuleDestroy(): Promise<void> {
		this.stopTimerUpdateLoop();
		await super.onModuleDestroy();
	}

	/**
	 * Start the background timer update loop
	 */
	private startTimerUpdateLoop() {
		if (this.timerUpdateInterval) return;

		this.timerUpdateInterval = setInterval(async () => {
			await this.updateAllActiveTimers();
		}, this.UPDATE_INTERVAL_MS);

		this.logger.log('Timer update loop started');
	}

	/**
	 * Stop the background timer update loop
	 */
	private stopTimerUpdateLoop() {
		if (this.timerUpdateInterval) {
			clearInterval(this.timerUpdateInterval);
			this.timerUpdateInterval = null;
			this.logger.log('Timer update loop stopped');
		}
	}

	/**
	 * Update all active timer messages
	 */
	private async updateAllActiveTimers() {
		for (const [timerId, tracker] of this.activeTimerMessages) {
			try {
				await this.updateTimerMessage(tracker);
			} catch (error) {
				this.logger.error(`Failed to update timer ${timerId}:`, error);
				// Remove tracker on persistent errors
				this.activeTimerMessages.delete(timerId);
			}
		}
	}

	/**
	 * Update a single timer message
	 */
	private async updateTimerMessage(tracker: TimerMessageTracker) {
		try {
			// Get current timer state from API
			const timer = await this.clockService.getTimer(tracker.timerId, tracker.token);

			if (!timer) {
				// Timer deleted, remove tracking and restore topic
				this.activeTimerMessages.delete(tracker.timerId);
				await this.restoreRoomTopic(tracker.roomId);
				return;
			}

			// Calculate remaining time
			const remainingSeconds = this.calculateRemainingSeconds(timer);

			if (timer.status === 'finished' || remainingSeconds <= 0) {
				// Timer finished - send final message, restore topic, and stop tracking
				const finalMessage = this.formatTimerFinishedMessage(tracker);
				await this.editMessage(tracker.roomId, tracker.eventId, finalMessage);
				await this.restoreRoomTopic(tracker.roomId);
				this.activeTimerMessages.delete(tracker.timerId);
				return;
			}

			if (timer.status === 'paused') {
				// Timer paused - update message and topic but keep tracking
				const pausedMessage = this.formatTimerMessage(
					remainingSeconds,
					tracker.durationSeconds,
					tracker.label,
					'paused'
				);
				await this.editMessage(tracker.roomId, tracker.eventId, pausedMessage);
				await this.updateRoomTopicWithTimer(
					tracker.roomId,
					tracker.timerId,
					remainingSeconds,
					tracker.durationSeconds,
					tracker.label,
					'paused'
				);
				return;
			}

			// Timer running - update message and topic with current progress
			const runningMessage = this.formatTimerMessage(
				remainingSeconds,
				tracker.durationSeconds,
				tracker.label,
				'running'
			);
			await this.editMessage(tracker.roomId, tracker.eventId, runningMessage);
			await this.updateRoomTopicWithTimer(
				tracker.roomId,
				tracker.timerId,
				remainingSeconds,
				tracker.durationSeconds,
				tracker.label,
				'running'
			);
		} catch (error) {
			// Token might have expired or API error
			this.logger.warn(`Timer update failed for ${tracker.timerId}: ${error}`);
			throw error;
		}
	}

	/**
	 * Calculate remaining seconds for a timer
	 */
	private calculateRemainingSeconds(timer: Timer): number {
		if (timer.status === 'paused') {
			return timer.remainingSeconds;
		}

		if (timer.status === 'running' && timer.startedAt) {
			const startedAt = new Date(timer.startedAt).getTime();
			const now = Date.now();
			const elapsedSeconds = Math.floor((now - startedAt) / 1000);
			return Math.max(0, timer.durationSeconds - elapsedSeconds);
		}

		return timer.remainingSeconds || timer.durationSeconds;
	}

	/**
	 * Format a timer message with progress bar
	 */
	private formatTimerMessage(
		remainingSeconds: number,
		totalSeconds: number,
		label: string | null,
		status: 'running' | 'paused'
	): string {
		const remaining = this.clockService.formatDuration(remainingSeconds);
		const total = this.clockService.formatDuration(totalSeconds);
		const progress = this.createProgressBar(remainingSeconds, totalSeconds);
		const percentage = Math.round((1 - remainingSeconds / totalSeconds) * 100);

		const statusIcon = status === 'running' ? '▶️' : '⏸️';
		const statusText = status === 'running' ? 'läuft' : 'pausiert';

		let message = `${statusIcon} **Timer ${statusText}**\n\n`;
		message += `⏱️ **${remaining}** / ${total}\n`;
		message += `${progress} ${percentage}%`;

		if (label) {
			message += `\n📝 ${label}`;
		}

		if (status === 'running') {
			message += '\n\n`!stop` zum Pausieren';
		} else {
			message += '\n\n`!resume` zum Fortsetzen';
		}

		return message;
	}

	/**
	 * Format timer finished message
	 */
	private formatTimerFinishedMessage(tracker: TimerMessageTracker): string {
		const total = this.clockService.formatDuration(tracker.durationSeconds);

		let message = '🎉 **Timer abgelaufen!**\n\n';
		message += `⏱️ ${total} vergangen`;

		if (tracker.label) {
			message += `\n📝 ${tracker.label}`;
		}

		message += '\n\n`!timer` für neuen Timer';

		return message;
	}

	/**
	 * Create a progress bar using Unicode block characters
	 */
	private createProgressBar(remaining: number, total: number, width: number = 20): string {
		const elapsed = total - remaining;
		const filledCount = Math.round((elapsed / total) * width);
		const emptyCount = width - filledCount;

		const filled = '█'.repeat(filledCount);
		const empty = '░'.repeat(emptyCount);

		return `${filled}${empty}`;
	}

	/**
	 * Get current room topic
	 */
	private async getRoomTopic(roomId: string): Promise<string> {
		try {
			const client = this.getClient();
			const state = await client.getRoomStateEvent(roomId, 'm.room.topic', '');
			return state?.topic || '';
		} catch {
			// Room might not have a topic set
			return '';
		}
	}

	/**
	 * Set room topic
	 */
	private async setRoomTopic(roomId: string, topic: string): Promise<void> {
		try {
			const client = this.getClient();
			this.logger.log(`Attempting to set room topic for ${roomId}: ${topic}`);
			await client.sendStateEvent(roomId, 'm.room.topic', '', { topic });
			this.logger.log(`Room topic updated: ${topic}`);
		} catch (error: unknown) {
			// Log full error details including Matrix errcode
			const errorDetails =
				error && typeof error === 'object'
					? JSON.stringify(error, null, 2)
					: String(error);
			this.logger.error(
				`Failed to set room topic for ${roomId}. Topic: "${topic}". Error: ${errorDetails}`
			);
		}
	}

	/**
	 * Format timer status for room topic
	 */
	private formatTimerTopic(
		remainingSeconds: number,
		totalSeconds: number,
		label: string | null,
		status: 'running' | 'paused'
	): string {
		const remaining = this.clockService.formatDuration(remainingSeconds);
		const percentage = Math.round((1 - remainingSeconds / totalSeconds) * 100);

		const statusIcon = status === 'running' ? '▶️' : '⏸️';
		let topic = `${statusIcon} Timer: ${remaining} (${percentage}%)`;

		if (label) {
			topic += ` - ${label}`;
		}

		return topic;
	}

	/**
	 * Update room topic with timer status
	 */
	private async updateRoomTopicWithTimer(
		roomId: string,
		timerId: string,
		remainingSeconds: number,
		totalSeconds: number,
		label: string | null,
		status: 'running' | 'paused'
	): Promise<void> {
		this.logger.log(`updateRoomTopicWithTimer called: room=${roomId}, timer=${timerId}, status=${status}`);

		// Save original topic if not already saved for this room
		if (!this.originalRoomTopics.has(roomId)) {
			const originalTopic = await this.getRoomTopic(roomId);
			this.originalRoomTopics.set(roomId, { originalTopic, timerId });
			this.logger.log(`Saved original topic: "${originalTopic}"`);
		}

		// Update topic with timer status
		const timerTopic = this.formatTimerTopic(remainingSeconds, totalSeconds, label, status);
		await this.setRoomTopic(roomId, timerTopic);
	}

	/**
	 * Restore original room topic when timer ends
	 */
	private async restoreRoomTopic(roomId: string): Promise<void> {
		const tracker = this.originalRoomTopics.get(roomId);
		if (tracker) {
			await this.setRoomTopic(roomId, tracker.originalTopic);
			this.originalRoomTopics.delete(roomId);
			this.logger.log(`Restored original topic for room ${roomId}`);
		}
	}

	protected getConfig(): MatrixBotConfig {
		return {
			homeserverUrl:
				this.configService.get<string>('matrix.homeserverUrl') || 'http://localhost:8008',
			accessToken: this.configService.get<string>('matrix.accessToken') || '',
			storagePath:
				this.configService.get<string>('matrix.storagePath') || './data/bot-storage.json',
			allowedRooms: this.configService.get<string[]>('matrix.allowedRooms') || [],
		};
	}

	protected getIntroductionMessage(): string | null {
		return WELCOME_TEXT;
	}

	protected async handleTextMessage(
		roomId: string,
		event: MatrixRoomEvent,
		message: string,
		sender: string
	): Promise<void> {
		// Check keywords first
		const keywordCommand = this.keywordDetector.detect(message);
		if (keywordCommand) {
			await this.executeCommand(roomId, event, sender, keywordCommand, '');
			return;
		}

		// Handle ! commands
		if (message.startsWith('!')) {
			const [command, ...args] = message.slice(1).split(' ');
			await this.executeCommand(roomId, event, sender, command.toLowerCase(), args.join(' '));
			return;
		}

		// Try to parse as natural timer/alarm command
		await this.handleNaturalLanguage(roomId, event, sender, message);
	}

	protected async handleAudioMessage(
		roomId: string,
		event: MatrixRoomEvent,
		sender: string
	): Promise<void> {
		try {
			await this.sendReply(roomId, event, 'Verarbeite Sprachnotiz...');

			const mxcUrl = event.content.url;
			if (!mxcUrl) {
				await this.sendReply(roomId, event, 'Keine Audio-URL gefunden.');
				return;
			}

			const buffer = await this.downloadMedia(mxcUrl);
			const transcription = await this.transcriptionService.transcribe(buffer);

			if (!transcription.trim()) {
				await this.sendReply(roomId, event, 'Konnte keine Sprache erkennen.');
				return;
			}

			this.logger.log(`Transcription: ${transcription}`);

			// Try to parse as command
			const lower = transcription.toLowerCase();

			// Check for timer
			const duration = this.clockService.parseDuration(transcription);
			if (
				duration &&
				(lower.includes('timer') ||
					lower.includes('minute') ||
					lower.includes('stunde') ||
					lower.match(/\d+\s*(m|min|h)/))
			) {
				await this.sendReply(roomId, event, `"${transcription}"`);
				await this.handleTimerCommand(roomId, event, sender, transcription);
				return;
			}

			// Check for alarm
			const time = this.clockService.parseAlarmTime(transcription);
			if (time && (lower.includes('wecker') || lower.includes('alarm') || lower.includes('uhr'))) {
				await this.sendReply(roomId, event, `"${transcription}"`);
				await this.handleAlarmCommand(roomId, event, sender, transcription);
				return;
			}

			// Check for stop/status commands
			if (lower.includes('stop') || lower.includes('stopp') || lower.includes('pause')) {
				await this.sendReply(roomId, event, `"${transcription}"`);
				await this.handleStopCommand(roomId, event, sender);
				return;
			}

			if (lower.includes('status') || lower.includes('wie viel')) {
				await this.sendReply(roomId, event, `"${transcription}"`);
				await this.handleStatusCommand(roomId, event, sender);
				return;
			}

			await this.sendReply(
				roomId,
				event,
				`"${transcription}"\n\nKonnte Befehl nicht verstehen. Versuche "Timer 25 Minuten" oder "Wecker 7 Uhr".`
			);
		} catch (error) {
			this.logger.error('Audio processing failed:', error);
			await this.sendReply(roomId, event, 'Fehler bei der Sprachverarbeitung.');
		}
	}

	private async executeCommand(
		roomId: string,
		event: MatrixRoomEvent,
		userId: string,
		command: string,
		args: string
	) {
		switch (command) {
			case 'help':
			case 'hilfe':
				await this.sendReply(roomId, event, HELP_TEXT);
				break;

			case 'timer':
				await this.handleTimerCommand(roomId, event, userId, args);
				break;

			case 'stop':
			case 'stopp':
			case 'pause':
				await this.handleStopCommand(roomId, event, userId);
				break;

			case 'resume':
			case 'weiter':
				await this.handleResumeCommand(roomId, event, userId);
				break;

			case 'reset':
				await this.handleResetCommand(roomId, event, userId);
				break;

			case 'status':
				await this.handleStatusCommand(roomId, event, userId);
				break;

			case 'timers':
				await this.handleTimersCommand(roomId, event, userId);
				break;

			case 'alarm':
			case 'wecker':
				await this.handleAlarmCommand(roomId, event, userId, args);
				break;

			case 'alarms':
			case 'alarme':
				await this.handleAlarmsCommand(roomId, event, userId);
				break;

			case 'zeit':
			case 'time':
				await this.handleTimeCommand(roomId, event, userId);
				break;

			case 'weltuhr':
				await this.handleWorldClockCommand(roomId, event, userId, args);
				break;

			case 'weltuhren':
				await this.handleWorldClocksCommand(roomId, event, userId);
				break;

			case 'language':
			case 'sprache':
			case 'lang':
				await this.handleLanguage(roomId, event, userId, args);
				break;

			case 'widget':
				await this.handleWidgetCommand(roomId, event, userId);
				break;

			default:
				// Silently ignore unknown commands
				break;
		}
	}

	private async handleTimerCommand(
		roomId: string,
		event: MatrixRoomEvent,
		userId: string,
		args: string
	) {
		if (!args.trim()) {
			await this.sendReply(
				roomId,
				event,
				'**Verwendung:** `!timer 25m` oder `!timer 1h30m`\n\nBeispiele:\n- `!timer 25` (25 Minuten)\n- `!timer 1h` (1 Stunde)\n- `!timer 90m Pomodoro` (90 Min mit Label)'
			);
			return;
		}

		const durationSeconds = this.clockService.parseDuration(args);
		if (!durationSeconds) {
			await this.sendReply(roomId, event, 'Konnte Zeit nicht verstehen. Beispiel: `!timer 25m`');
			return;
		}

		// Extract label if present (everything after the duration)
		const label = args.replace(/[\d\s]*[hms]+/gi, '').trim() || null;

		try {
			const token = await this.requireLogin(roomId, event, userId);
			if (!token) return;

			// Create and start timer
			const timer = await this.clockService.createTimer(durationSeconds, label, token);
			await this.clockService.startTimer(timer.id, token);

			// Format initial message with progress bar
			const initialMessage = this.formatTimerMessage(
				durationSeconds,
				durationSeconds,
				label,
				'running'
			);

			// Send message and track it for live updates
			const eventId = await this.sendReply(roomId, event, initialMessage);

			// Store tracking info for live updates
			this.activeTimerMessages.set(timer.id, {
				timerId: timer.id,
				roomId,
				eventId,
				userId,
				token,
				durationSeconds,
				label,
				startedAt: new Date(),
			});

			// Set initial room topic with timer status
			await this.updateRoomTopicWithTimer(
				roomId,
				timer.id,
				durationSeconds,
				durationSeconds,
				label,
				'running'
			);

			this.logger.log(`Started tracking timer ${timer.id} for live updates`);
		} catch (error) {
			this.logger.error('Timer creation failed:', error);
			await this.sendReply(roomId, event, 'Fehler beim Erstellen des Timers.');
		}
	}

	private async handleStopCommand(roomId: string, event: MatrixRoomEvent, userId: string) {
		try {
			const token = await this.requireLogin(roomId, event, userId);
			if (!token) return;

			const runningTimer = await this.clockService.getRunningTimer(token);
			if (!runningTimer) {
				await this.sendReply(roomId, event, 'Kein laufender Timer.');
				return;
			}

			if (runningTimer.status === 'paused') {
				await this.sendReply(
					roomId,
					event,
					'Timer ist bereits pausiert. `!resume` zum Fortsetzen.'
				);
				return;
			}

			const timer = await this.clockService.pauseTimer(runningTimer.id, token);
			const remaining = this.clockService.formatDuration(timer.remainingSeconds);

			await this.sendReply(
				roomId,
				event,
				`**Timer pausiert**\n\nVerbleibend: ${remaining}\n\n\`!resume\` zum Fortsetzen, \`!reset\` zum Zurucksetzen`
			);
		} catch (error) {
			this.logger.error('Stop failed:', error);
			await this.sendReply(roomId, event, 'Fehler beim Pausieren.');
		}
	}

	private async handleResumeCommand(roomId: string, event: MatrixRoomEvent, userId: string) {
		try {
			const token = await this.requireLogin(roomId, event, userId);
			if (!token) return;

			const pausedTimer = await this.clockService.getRunningTimer(token);
			if (!pausedTimer || pausedTimer.status !== 'paused') {
				await this.sendReply(roomId, event, 'Kein pausierter Timer.');
				return;
			}

			const timer = await this.clockService.startTimer(pausedTimer.id, token);
			const remaining = this.clockService.formatDuration(timer.remainingSeconds);

			await this.sendReply(roomId, event, `**Timer fortgesetzt**\n\nVerbleibend: ${remaining}`);
		} catch (error) {
			this.logger.error('Resume failed:', error);
			await this.sendReply(roomId, event, 'Fehler beim Fortsetzen.');
		}
	}

	private async handleResetCommand(roomId: string, event: MatrixRoomEvent, userId: string) {
		try {
			const token = await this.requireLogin(roomId, event, userId);
			if (!token) return;

			const activeTimer = await this.clockService.getRunningTimer(token);
			if (!activeTimer) {
				await this.sendReply(roomId, event, 'Kein aktiver Timer.');
				return;
			}

			await this.clockService.resetTimer(activeTimer.id, token);
			await this.sendReply(roomId, event, 'Timer zuruckgesetzt.');
		} catch (error) {
			this.logger.error('Reset failed:', error);
			await this.sendReply(roomId, event, 'Fehler beim Zurucksetzen.');
		}
	}

	private async handleStatusCommand(roomId: string, event: MatrixRoomEvent, userId: string) {
		// Auth-Status zuerst
		const loggedIn = await this.sessionService.isLoggedIn(userId);
		const session = await this.sessionService.getSession(userId);
		const token = await this.sessionService.getToken(userId);

		let response = '**🕐 Clock Bot Status**\n\n';

		if (loggedIn && session && token) {
			const balance = await this.creditService.getBalance(token);
			response += `👤 Angemeldet als: ${session.email}\n`;
			response += `⚡ Credits: ${balance.balance.toFixed(2)}\n\n`;
		} else {
			response += `⚠️ Nicht verbunden - bitte in Element neu einloggen via "Mit Mana Core anmelden"\n\n`;
		}

		// Timer-Status
		try {
			const timerToken = await this.getToken(userId);
			if (timerToken) {
				const timer = await this.clockService.getRunningTimer(timerToken);
				if (timer) {
					const remaining = this.clockService.formatDuration(timer.remainingSeconds);
					const total = this.clockService.formatDuration(timer.durationSeconds);
					const statusIcon = timer.status === 'running' ? '▶️' : '⏸️';
					const statusText = timer.status === 'running' ? 'Läuft' : 'Pausiert';
					response += `**${statusIcon} Timer ${statusText}**\n`;
					response += `Verbleibend: ${remaining} / ${total}`;
					if (timer.label) response += `\nLabel: ${timer.label}`;
				} else {
					response += `Kein aktiver Timer.\n\nStarte einen mit \`!timer 25m\``;
				}
			} else {
				response += `Timer-Status nicht verfügbar (nicht angemeldet).`;
			}
		} catch (error) {
			this.logger.error('Timer status failed:', error);
			response += `Timer-Status nicht verfügbar.`;
		}

		await this.sendReply(roomId, event, response);
	}

	private async handleTimersCommand(roomId: string, event: MatrixRoomEvent, userId: string) {
		try {
			const token = await this.requireLogin(roomId, event, userId);
			if (!token) return;

			const timers = await this.clockService.getTimers(token);
			if (timers.length === 0) {
				await this.sendReply(roomId, event, 'Keine Timer.\n\nErstelle einen mit `!timer 25m`');
				return;
			}

			let response = '**Deine Timer:**\n\n';
			timers.forEach((t, i) => {
				const duration = this.clockService.formatDuration(t.durationSeconds);
				const statusIcon = t.status === 'running' ? '' : t.status === 'paused' ? '' : '';
				const label = t.label ? ` - ${t.label}` : '';
				response += `${i + 1}. ${statusIcon} ${duration}${label}\n`;
			});

			await this.sendReply(roomId, event, response);
		} catch (error) {
			this.logger.error('Timers list failed:', error);
			await this.sendReply(roomId, event, 'Fehler beim Abrufen der Timer.');
		}
	}

	private async handleAlarmCommand(
		roomId: string,
		event: MatrixRoomEvent,
		userId: string,
		args: string
	) {
		const parts = args.trim().split(' ');

		// Handle !alarm off/on/delete commands
		if (parts[0] === 'off' || parts[0] === 'on' || parts[0] === 'delete') {
			// TODO: Implement alarm management
			await this.sendReply(roomId, event, 'Alarm-Verwaltung kommt bald!');
			return;
		}

		const time = this.clockService.parseAlarmTime(args);
		if (!time) {
			await this.sendReply(
				roomId,
				event,
				'**Verwendung:** `!alarm 07:30` oder `!alarm 7 Uhr 30`\n\nBeispiel: `!alarm 06:00 Aufstehen!`'
			);
			return;
		}

		// Extract label (everything after the time)
		const label = args.replace(/[\d:]+\s*(uhr\s*\d*)?/gi, '').trim() || null;

		try {
			const token = await this.requireLogin(roomId, event, userId);
			if (!token) return;

			await this.clockService.createAlarm(time, label, token);
			let response = `**Alarm gestellt!**\n\nZeit: ${time.substring(0, 5)} Uhr`;
			if (label) response += `\nLabel: ${label}`;

			await this.sendReply(roomId, event, response);
		} catch (error) {
			this.logger.error('Alarm creation failed:', error);
			await this.sendReply(roomId, event, 'Fehler beim Erstellen des Alarms.');
		}
	}

	private async handleAlarmsCommand(roomId: string, event: MatrixRoomEvent, userId: string) {
		try {
			const token = await this.requireLogin(roomId, event, userId);
			if (!token) return;

			const alarms = await this.clockService.getAlarms(token);
			if (alarms.length === 0) {
				await this.sendReply(roomId, event, 'Keine Alarme.\n\nErstelle einen mit `!alarm 07:30`');
				return;
			}

			let response = '**Deine Alarme:**\n\n';
			alarms.forEach((a, i) => {
				const time = a.time.substring(0, 5);
				const enabledIcon = a.enabled ? '' : '';
				const label = a.label ? ` - ${a.label}` : '';
				response += `${i + 1}. ${enabledIcon} ${time} Uhr${label}\n`;
			});

			await this.sendReply(roomId, event, response);
		} catch (error) {
			this.logger.error('Alarms list failed:', error);
			await this.sendReply(roomId, event, 'Fehler beim Abrufen der Alarme.');
		}
	}

	private async handleTimeCommand(roomId: string, event: MatrixRoomEvent, userId: string) {
		const now = new Date();
		const timeStr = now.toLocaleTimeString('de-DE', { hour: '2-digit', minute: '2-digit' });
		const dateStr = now.toLocaleDateString('de-DE', {
			weekday: 'long',
			day: 'numeric',
			month: 'long',
		});

		let response = `**${timeStr} Uhr**\n${dateStr}`;

		try {
			const token = await this.getToken(userId);
			if (token) {
				const worldClocks = await this.clockService.getWorldClocks(token);
				if (worldClocks.length > 0) {
					response += '\n\n**Weltuhren:**';
					for (const wc of worldClocks) {
						const wcTime = new Date().toLocaleTimeString('de-DE', {
							hour: '2-digit',
							minute: '2-digit',
							timeZone: wc.timezone,
						});
						response += `\n${wc.cityName}: ${wcTime}`;
					}
				}
			}
		} catch {
			// Ignore world clock errors
		}

		await this.sendReply(roomId, event, response);
	}

	private async handleWorldClockCommand(
		roomId: string,
		event: MatrixRoomEvent,
		userId: string,
		args: string
	) {
		if (!args.trim()) {
			await this.sendReply(
				roomId,
				event,
				'**Verwendung:** `!weltuhr Berlin` oder `!weltuhr New York`'
			);
			return;
		}

		try {
			const results = await this.clockService.searchTimezones(args);
			if (results.length === 0) {
				await this.sendReply(roomId, event, `Keine Zeitzone fur "${args}" gefunden.`);
				return;
			}

			const token = await this.requireLogin(roomId, event, userId);
			if (!token) return;

			const best = results[0];
			await this.clockService.addWorldClock(best.timezone, best.city, token);
			await this.sendReply(roomId, event, `**Weltuhr hinzugefugt:** ${best.city}`);
		} catch (error) {
			this.logger.error('World clock add failed:', error);
			await this.sendReply(roomId, event, 'Fehler beim Hinzufugen der Weltuhr.');
		}
	}

	private async handleWorldClocksCommand(roomId: string, event: MatrixRoomEvent, userId: string) {
		try {
			const token = await this.requireLogin(roomId, event, userId);
			if (!token) return;

			const clocks = await this.clockService.getWorldClocks(token);
			if (clocks.length === 0) {
				await this.sendReply(
					roomId,
					event,
					'Keine Weltuhren.\n\nFuge eine hinzu mit `!weltuhr Berlin`'
				);
				return;
			}

			let response = '**Deine Weltuhren:**\n\n';
			for (const wc of clocks) {
				const time = new Date().toLocaleTimeString('de-DE', {
					hour: '2-digit',
					minute: '2-digit',
					timeZone: wc.timezone,
				});
				response += `${wc.cityName}: **${time}**\n`;
			}

			await this.sendReply(roomId, event, response);
		} catch (error) {
			this.logger.error('World clocks list failed:', error);
			await this.sendReply(roomId, event, 'Fehler beim Abrufen der Weltuhren.');
		}
	}

	private async handleNaturalLanguage(
		roomId: string,
		event: MatrixRoomEvent,
		userId: string,
		text: string
	) {
		const lower = text.toLowerCase();

		// Try to detect timer intent
		if (
			lower.includes('timer') ||
			lower.includes('stoppuhr') ||
			lower.match(/start\s*\d+/) ||
			lower.match(/\d+\s*(min|m|h|stunde)/)
		) {
			const duration = this.clockService.parseDuration(text);
			if (duration) {
				await this.handleTimerCommand(roomId, event, userId, text);
				return;
			}
		}

		// Try to detect alarm intent
		if (
			lower.includes('wecker') ||
			lower.includes('alarm') ||
			lower.includes('weck mich') ||
			lower.match(/\d{1,2}:\d{2}/) ||
			lower.match(/\d{1,2}\s*uhr/)
		) {
			const time = this.clockService.parseAlarmTime(text);
			if (time) {
				await this.handleAlarmCommand(roomId, event, userId, text);
				return;
			}
		}

		// Fallback: try to parse any message as a timer duration
		const duration = this.clockService.parseDuration(text);
		if (duration) {
			await this.handleTimerCommand(roomId, event, userId, text);
			return;
		}
	}

	private async getToken(userId: string): Promise<string | null> {
		// SessionService hat Priorität (Login via mana-core-auth)
		const sessionToken = await this.sessionService.getToken(userId);
		if (sessionToken) return sessionToken;

		// Fallback auf clockService Token
		const storedToken = this.clockService.getUserToken(userId);
		if (storedToken) return storedToken;

		// Entwicklungs-Fallback
		return this.demoToken || null;
	}

	/**
	 * Require login - returns token or sends login prompt and returns null
	 */
	private async requireLogin(
		roomId: string,
		event: MatrixRoomEvent,
		userId: string
	): Promise<string | null> {
		const token = await this.getToken(userId);
		if (!token) {
			await this.sendReply(roomId, event, LOGIN_MESSAGES.clock);
			return null;
		}
		return token;
	}

	private async handleLanguage(
		roomId: string,
		event: MatrixRoomEvent,
		userId: string,
		args: string
	) {
		const lang = args.trim().toLowerCase();

		if (!lang) {
			const currentLang = await this.i18nService.getLanguage(userId);
			const langName = LANGUAGE_NAMES[currentLang];
			const available = this.i18nService
				.getAvailableLanguages()
				.map((l) => `${l} (${LANGUAGE_NAMES[l]})`)
				.join(', ');
			await this.sendReply(
				roomId,
				event,
				`**Sprache / Language:** ${langName}\n\n**Verfügbar / Available:** ${available}\n\nÄndern / Change: \`!language de\` oder / or \`!language en\``
			);
			return;
		}

		if (!this.i18nService.isValidLanguage(lang)) {
			const available = this.i18nService.getAvailableLanguages().join(', ');
			await this.sendReply(
				roomId,
				event,
				`Unbekannte Sprache / Unknown language: ${lang}\n\nVerfügbar / Available: ${available}`
			);
			return;
		}

		await this.i18nService.setLanguage(userId, lang as Language);
		const langName = LANGUAGE_NAMES[lang as Language];

		if (lang === 'de') {
			await this.sendReply(roomId, event, `Sprache geändert zu: **${langName}**`);
		} else {
			await this.sendReply(roomId, event, `Language changed to: **${langName}**`);
		}
	}

	/**
	 * Handle widget command - adds a timer widget to the room
	 */
	private async handleWidgetCommand(roomId: string, event: MatrixRoomEvent, userId: string) {
		try {
			const widgetBaseUrl =
				this.configService.get<string>('widget.publicUrl') || 'http://localhost:3317/widget';

			// Widget URL with Matrix variables that Element substitutes
			const widgetUrl = `${widgetBaseUrl}?userId=$matrix_user_id&roomId=$matrix_room_id`;

			// Generate unique widget ID
			const widgetId = `clock-timer-widget-${roomId.replace(/[^a-zA-Z0-9]/g, '')}`;

			// Widget state event content
			const widgetContent = {
				type: 'm.custom',
				url: widgetUrl,
				name: 'Timer Widget',
				data: {
					title: 'Clock Bot Timer',
				},
				creatorUserId: this.botUserId,
				id: widgetId,
			};

			// Send state event to add widget
			await this.getClient().sendStateEvent(
				roomId,
				'im.vector.modular.widgets',
				widgetId,
				widgetContent
			);

			await this.sendReply(
				roomId,
				event,
				'**Timer Widget hinzugefügt!**\n\n' +
					'Das Widget zeigt deinen Timer-Status in der Seitenleiste an.\n\n' +
					'Falls es nicht sichtbar ist:\n' +
					'1. Klicke auf das **Info-Symbol** (i) oben rechts\n' +
					'2. Wähle **Widgets**\n' +
					'3. Das Timer Widget sollte sichtbar sein'
			);
		} catch (error) {
			this.logger.error('Widget creation failed:', error);

			// Fallback: Give manual instructions
			const widgetBaseUrl =
				this.configService.get<string>('widget.publicUrl') || 'http://localhost:3317/widget';
			await this.sendReply(
				roomId,
				event,
				'**Widget konnte nicht automatisch hinzugefügt werden.**\n\n' +
					'Du kannst es manuell hinzufügen:\n' +
					`1. In Element: \`/addwidget ${widgetBaseUrl}\`\n` +
					'2. Oder über Raum-Einstellungen → Widgets'
			);
		}
	}
}
