import type { Database } from 'bun:sqlite';
import { ensureUserExists } from '../db';
import { isGroupId } from '../utils/whatsapp';
import { AllowedGroups } from './allowed-groups';
import { Metrics } from './metrics';
import { route as routeCommand } from './commands';
import { ACTION_ALIASES } from './commands/shared';
import { getDb } from '../db/locator';

type CommandContext = {
	sender: string;     // normalized user id (digits only), but accept raw too
	groupId: string;    // full JID (e.g., xxx@g.us)
	message: string;    // raw message text
	mentions: string[]; // array of raw JIDs mentioned
	messageId?: string; // id del mensaje origen (para task_origins y reacciones)
	participant?: string; // JID del autor del mensaje origen (en grupos)
	fromMe?: boolean;     // si el mensaje origen fue enviado por la instancia
};

export type CommandResponse = {
	recipient: string;
	message: string;
	mentions?: string[]; // full JIDs to mention in the outgoing message
};

export type CommandOutcome = {
	responses: CommandResponse[];
	ok: boolean;
	createdTaskIds?: number[];
};

export class CommandService {

	static async handle(context: CommandContext): Promise<CommandResponse[]> {
		const outcome = await this.handleWithOutcome(context);
		return outcome.responses;
	}

	static async handleWithOutcome(context: CommandContext): Promise<CommandOutcome> {
		const msg = (context.message || '').trim();
		const instanceDb = getDb() as Database;
		if (!/^(tarea|t) /i.test(msg)) {
			return { responses: [], ok: true };
		}

		// Registrar interacción del usuario (last_command_at) para cualquier comando t …
		try {
			let usersTableExists = false;
			try {
				const row = instanceDb.query(`SELECT name FROM sqlite_master WHERE type='table' AND name='users'`).get() as { name?: string } | undefined;
				usersTableExists = !!row;
			} catch {}
			if (usersTableExists) {
				const ensured = ensureUserExists(context.sender, instanceDb);
				if (ensured) {
					try {
						instanceDb.prepare(`UPDATE users SET last_command_at = strftime('%Y-%m-%d %H:%M:%f','now') WHERE id = ?`).run(ensured);
					} catch {}
				}
			}
		} catch {}

		// Gating de grupos en modo 'enforce' (cuando CommandService se invoca directamente)
		if (isGroupId(context.groupId)) {
			const mode = String(process.env.GROUP_GATING_MODE || 'off').toLowerCase();
			if (mode === 'enforce') {
				try {
					if (!AllowedGroups.isAllowed(context.groupId)) {
						try { Metrics.inc('commands_blocked_total'); } catch { }
						return { responses: [], ok: true };
					}
				} catch {
					// Si falla el check, ser permisivos
				}
			}
		}

		try {
			const routed = await routeCommand(context, { db: instanceDb });
			const responses = routed ?? [];

			// Clasificación explícita del outcome (evita lógica en server)
			const tokens = msg.split(/\s+/);
			const rawAction = (tokens[1] || '').toLowerCase();
			const action = ACTION_ALIASES[rawAction] || rawAction;

			// Casos explícitos considerados éxito
			if (!action || action === 'ayuda' || action === 'web') {
				return { responses, ok: true };
			}

			const lowerMsgs = (responses || []).map(r => String(r?.message || '').toLowerCase());

			const isOkException = (m: string) =>
				m.includes('ya estaba completada') ||
				m.includes('ya la tenías') ||
				m.includes('no la tenías');

			const isErrorMsg = (m: string) =>
				m.startsWith('ℹ️ uso:'.toLowerCase()) ||
				m.includes('uso:') ||
				m.includes('no puedes') ||
				m.includes('no permitido') ||
				m.includes('no encontrada') ||
				m.includes('comando no reconocido');

			let hasError = false;
			for (const m of lowerMsgs) {
				if (isErrorMsg(m) && !isOkException(m)) {
					hasError = true;
					break;
				}
			}

			return { responses, ok: !hasError };
		} catch (error) {
			return {
				responses: [{
					recipient: context.sender,
					message: 'Error processing command'
				}],
				ok: false
			};
		}
	}
}
