import { systemEvents, EVENTS } from "@shared/lib/events";
import type { DomainEventPayloads } from "@shared/lib/events";
import { questService } from "@shared/modules/quest/quest.service";
import { dashboardService } from "@shared/modules/dashboard/dashboard.service";

/**
 * Registers all domain event listeners.
 * Must be called once at startup before any domain events are emitted.
 *
 * This wiring replaces dynamic imports that were previously used to avoid
 * circular dependencies between services (e.g., economy -> quest -> economy).
 */

function fireAndForget(fn: () => Promise<void>) {
    fn().catch(err => console.error("[EventWiring] Fire-and-forget handler failed:", err));
}

let registered = false;
export function registerDomainEventListeners() {
    if (registered) return;
    registered = true;

    // --- Quest progress tracking (awaited via emitAsync to preserve tx atomicity) ---

    systemEvents.on(EVENTS.DOMAIN.BALANCE_CHANGED, async (payload: DomainEventPayloads[typeof EVENTS.DOMAIN.BALANCE_CHANGED]) => {
        await questService.handleEvent(payload.userId, payload.type, 1, payload.tx);
    });

    systemEvents.on(EVENTS.DOMAIN.XP_GAINED, async (payload: DomainEventPayloads[typeof EVENTS.DOMAIN.XP_GAINED]) => {
        await questService.handleEvent(payload.userId, 'XP_GAIN', payload.amount, payload.tx);
    });

    systemEvents.on(EVENTS.DOMAIN.ITEM_COLLECTED, async (payload: DomainEventPayloads[typeof EVENTS.DOMAIN.ITEM_COLLECTED]) => {
        await questService.handleEvent(payload.userId, `ITEM_COLLECT:${payload.itemId}`, payload.quantity, payload.tx);
    });

    systemEvents.on(EVENTS.DOMAIN.ITEM_USED, async (payload: DomainEventPayloads[typeof EVENTS.DOMAIN.ITEM_USED]) => {
        await questService.handleEvent(payload.userId, `ITEM_USE:${payload.itemId}`, 1, payload.tx);
    });

    systemEvents.on(EVENTS.DOMAIN.TRANSFER_COMPLETED, async (payload: DomainEventPayloads[typeof EVENTS.DOMAIN.TRANSFER_COMPLETED]) => {
        await questService.handleEvent(payload.userId, 'TRANSFER_OUT', 1, payload.tx);
    });

    systemEvents.on(EVENTS.DOMAIN.DAILY_CLAIMED, async (payload: DomainEventPayloads[typeof EVENTS.DOMAIN.DAILY_CLAIMED]) => {
        await questService.handleEvent(payload.userId, 'DAILY_REWARD', 1, payload.tx);
    });

    systemEvents.on(EVENTS.DOMAIN.TRIVIA_WON, async (payload: DomainEventPayloads[typeof EVENTS.DOMAIN.TRIVIA_WON]) => {
        await questService.handleEvent(payload.userId, 'TRIVIA_WIN', 1, payload.tx);
    });

    systemEvents.on(EVENTS.DOMAIN.EXAM_PASSED, async (payload: DomainEventPayloads[typeof EVENTS.DOMAIN.EXAM_PASSED]) => {
        await questService.handleEvent(payload.userId, 'EXAM_REWARD', 1, payload.tx);
    });

    // --- Dashboard event recording (fire-and-forget) ---

    systemEvents.on(EVENTS.DOMAIN.TRANSFER_COMPLETED, (payload: DomainEventPayloads[typeof EVENTS.DOMAIN.TRANSFER_COMPLETED]) => {
        fireAndForget(async () => {
            await dashboardService.recordEvent({
                type: 'info',
                message: `${payload.username} transferred ${payload.amount.toLocaleString()} AU to User ID ${payload.toUserId}`,
                icon: '💸'
            });
        });
    });

    systemEvents.on(EVENTS.DOMAIN.DAILY_CLAIMED, (payload: DomainEventPayloads[typeof EVENTS.DOMAIN.DAILY_CLAIMED]) => {
        fireAndForget(async () => {
            await dashboardService.recordEvent({
                type: 'success',
                message: `${payload.username} claimed daily reward: ${payload.amount.toLocaleString()} AU`,
                icon: '☀️'
            });
        });
    });

    systemEvents.on(EVENTS.DOMAIN.TRIVIA_STARTED, (payload: DomainEventPayloads[typeof EVENTS.DOMAIN.TRIVIA_STARTED]) => {
        fireAndForget(async () => {
            await dashboardService.recordEvent({
                type: 'info',
                message: `${payload.username} started a trivia game (${payload.difficulty})`,
                icon: '🎯'
            });
        });
    });

    systemEvents.on(EVENTS.DOMAIN.TRIVIA_WON, (payload: DomainEventPayloads[typeof EVENTS.DOMAIN.TRIVIA_WON]) => {
        fireAndForget(async () => {
            await dashboardService.recordEvent({
                type: 'success',
                message: `${payload.username ?? 'Unknown user'} won ${payload.reward.toLocaleString()} AU from trivia!`,
                icon: '🎉'
            });
        });
    });

    systemEvents.on(EVENTS.DOMAIN.EXAM_PASSED, (payload: DomainEventPayloads[typeof EVENTS.DOMAIN.EXAM_PASSED]) => {
        fireAndForget(async () => {
            await dashboardService.recordEvent({
                type: 'success',
                message: `${payload.username} passed their exam: ${payload.reward.toLocaleString()} AU`,
                icon: '🎓'
            });
        });
    });
}
