<script setup>
import { computed, inject, nextTick, onMounted, onUnmounted, ref, watch } from 'vue';
import { getConfig, getLang } from '../utils/config';
import { fullName, initials, formatTime, displayName } from '../utils/format';
import * as chatApi from '../api/chat';
import { REALTIME_KEY } from '../composables/useRealtime';
import ChatComposer from './ChatComposer.vue';

const config = getConfig();
const currentUserId = config.userId;
const typingTimeout = config.typingTimeoutMs || 2500;
const pollingFallbackMs = (config.pollingFallbackSeconds || 30) * 1000;

const colleagues = ref([]);
const rooms = ref([]);
const roomsLoading = ref(false);
const roomFilter = ref('all');
const roomSearch = ref('');
const messageSearch = ref('');
const currentRoomId = ref(null);
const currentRoom = ref(null);
const messages = ref([]);
const typingText = ref('');
const roomOpen = ref(false);
const sending = ref(false);

const showDirectModal = ref(false);
const showGroupModal = ref(false);
const showMembersModal = ref(false);
const directUserId = ref('');
const groupName = ref('');
const groupMemberIds = ref([]);
const addMemberUserId = ref('');

let typingClearTimer = null;
let lastTypingSent = 0;
let fallbackPollTimer = null;
let roomSearchTimer = null;
const messageBox = ref(null);
const composerRef = ref(null);

const realtime = inject(REALTIME_KEY);
let unregisterRealtime = null;

function handleMessage(payload, roomId) {
    const msg = payload?.message;
    if (!msg) return;

    updateRoomPreview(roomId, msg);

    if (parseInt(currentRoomId.value, 10) === parseInt(roomId, 10)) {
        appendMessage(msg);
        chatApi.markRead(roomId).catch(() => {});
    } else {
        bumpUnread(roomId);
    }
}

function handleTyping(payload, roomId) {
    const senderId = parseInt(payload?.user_id, 10);
    if (!senderId || senderId === parseInt(currentUserId, 10)) return;
    if (parseInt(currentRoomId.value, 10) !== parseInt(roomId, 10)) return;
    const name = payload.user_name || fullName(payload.user) || getLang('group', 'User');
    typingText.value = getLang('user_typing', ':name is typing...').replace(':name', name);
    clearTimeout(typingClearTimer);
    typingClearTimer = setTimeout(() => { typingText.value = ''; }, typingTimeout);
}

function handleConnected() {
    stopFallbackPolling();
}

function handleDisconnected() {
    startFallbackPolling();
}

function roomDisplayName(room) {
    if (room.type === 'group') return room.name || getLang('group', 'Group');
    const other = (room.members || []).find((m) => m.id !== currentUserId);
    return other ? fullName(other) : getLang('group', 'Group');
}

function isOtherOnline(room) {
    if (room.is_other_online !== undefined) return room.is_other_online;
    const other = (room.members || []).find((m) => m.id !== currentUserId);
    return other ? !!other.is_online : false;
}

const chatSubtitle = computed(() => {
    if (!currentRoom.value) return '';
    if (currentRoom.value.type === 'direct') {
        return isOtherOnline(currentRoom.value) ? getLang('online') : getLang('offline');
    }
    return `${(currentRoom.value.members || []).length} ${getLang('members', 'members')}`;
});

const isGroupChat = computed(() => currentRoom.value?.type === 'group');

function roomPreview(room) {
    const body = (room.latest_message || {}).body || '';
    if (!body) return '';
    if (room.type === 'group' && room.latest_message?.user) {
        const sender = displayName(room.latest_message.user, getLang('you'));
        return `${sender}: ${body}`;
    }
    return body;
}

function messageLabel(msg) {
    const mine = parseInt(msg.user_id, 10) === parseInt(currentUserId, 10);
    if (mine) return getLang('you');
    return displayName(msg.user);
}

function showMessageName(msg) {
    return isGroupChat.value || parseInt(msg.user_id, 10) !== parseInt(currentUserId, 10);
}

function colleagueLabel(user) {
    const name = fullName(user);
    const handle = user.username ? ` (@${user.username})` : '';
    return `${name}${handle}${user.is_online ? ' ●' : ''}`;
}

const canManageMembers = computed(() => currentRoom.value?.created_by === currentUserId);

const availableColleaguesForAdd = computed(() => {
    const existing = new Set((currentRoom.value?.members || []).map((m) => m.id));
    return colleagues.value.filter((c) => !existing.has(c.id));
});

function notifyError(message) {
    if (typeof window.toastr !== 'undefined') {
        window.toastr.error(message);
    } else {
        alert(message);
    }
}

function notifySuccess(message) {
    if (typeof window.toastr !== 'undefined') {
        window.toastr.success(message);
    }
}

function updateRoomPreview(roomId, msg) {
    rooms.value = rooms.value.map((r) => {
        if (parseInt(r.id, 10) !== parseInt(roomId, 10)) return r;
        return {
            ...r,
            latest_message: msg,
            last_message_at: msg.created_at,
        };
    });
}

function bumpUnread(roomId) {
    rooms.value = rooms.value.map((r) => {
        if (parseInt(r.id, 10) !== parseInt(roomId, 10)) return r;
        return { ...r, unread_count: (r.unread_count || 0) + 1 };
    });
}

function appendMessage(msg) {
    if (!msg?.body) return;
    if (messages.value.some((m) => m.id && msg.id && m.id === msg.id)) return;
    messages.value.push(msg);
    scrollToBottom();
}

async function scrollToBottom() {
    await nextTick();
    if (messageBox.value) {
        messageBox.value.scrollTop = messageBox.value.scrollHeight;
    }
}

async function loadColleagues() {
    colleagues.value = await chatApi.fetchColleagues();
}

async function loadRooms() {
    if (roomsLoading.value) return;
    roomsLoading.value = true;
    try {
        const data = await chatApi.fetchRooms({
            q: roomSearch.value.trim(),
            type: roomFilter.value === 'all' ? '' : roomFilter.value,
        });
        rooms.value = data || [];
        realtime.syncRoomSubscriptions(rooms.value.map((r) => r.id));
    } finally {
        roomsLoading.value = false;
    }
}

async function loadMessages(roomId) {
    const params = messageSearch.value.trim() ? { search: messageSearch.value.trim() } : {};
    messages.value = await chatApi.fetchMessages(roomId, params);
    await scrollToBottom();
}

async function openRoom(room) {
    currentRoomId.value = room.id;
    currentRoom.value = room;
    roomOpen.value = true;
    await loadMessages(room.id);
    await chatApi.markRead(room.id);
    rooms.value = rooms.value.map((r) => (
        parseInt(r.id, 10) === parseInt(room.id, 10) ? { ...r, unread_count: 0 } : r
    ));
    await nextTick();
    composerRef.value?.focus();
}

async function selectRoom(room) {
    try {
        if (!room.members?.length) {
            room = await chatApi.fetchRoom(room.id);
        }
        await openRoom(room);
    } catch {
        notifyError(getLang('send_failed'));
    }
}

function closeRoom() {
    roomOpen.value = false;
}

async function sendChatMessage(body) {
    if (!body.trim() || !currentRoomId.value || sending.value) return;
    sending.value = true;
    try {
        const msg = await chatApi.sendMessage(currentRoomId.value, body.trim());
        if (msg?.body) {
            appendMessage(msg);
            updateRoomPreview(currentRoomId.value, msg);
        } else {
            await loadMessages(currentRoomId.value);
        }
    } catch (err) {
        notifyError(err.response?.data?.message || getLang('send_failed'));
    } finally {
        sending.value = false;
    }
}

const composerText = ref('');

async function onSubmitMessage() {
    const text = composerText.value;
    if (!text.trim()) return;
    composerText.value = '';
    await sendChatMessage(text);
    composerRef.value?.focus();
}

function onComposerTyping() {
    if (!currentRoomId.value) return;
    const now = Date.now();
    if (now - lastTypingSent < 1500) return;
    lastTypingSent = now;
    realtime?.whisperTyping?.(currentRoomId.value);
}

async function createDirectRoom() {
    if (!directUserId.value) return;
    try {
        const room = await chatApi.createRoom({ type: 'direct', user_id: directUserId.value });
        showDirectModal.value = false;
        directUserId.value = '';
        await loadRooms();
        if (room?.id) await selectRoom(room);
    } catch (err) {
        notifyError(err.response?.data?.message || getLang('send_failed'));
    }
}

async function createGroupRoom() {
    if (!groupName.value.trim() || !groupMemberIds.value.length) return;
    try {
        const room = await chatApi.createRoom({
            type: 'group',
            name: groupName.value.trim(),
            member_ids: groupMemberIds.value,
        });
        showGroupModal.value = false;
        groupName.value = '';
        groupMemberIds.value = [];
        await loadRooms();
        if (room?.id) await selectRoom(room);
    } catch (err) {
        notifyError(err.response?.data?.message || getLang('send_failed'));
    }
}

async function openMembersModal() {
    if (!currentRoom.value && currentRoomId.value) {
        currentRoom.value = await chatApi.fetchRoom(currentRoomId.value);
    }
    showMembersModal.value = true;
}

async function addMember() {
    if (!addMemberUserId.value || !currentRoomId.value) return;
    try {
        currentRoom.value = await chatApi.addMember(currentRoomId.value, addMemberUserId.value);
        addMemberUserId.value = '';
        await loadRooms();
    } catch (err) {
        notifyError(err.response?.data?.message || getLang('send_failed'));
    }
}

async function removeMember(userId) {
    if (!currentRoomId.value) return;
    try {
        const room = await chatApi.removeMember(currentRoomId.value, userId);
        if (parseInt(userId, 10) === parseInt(currentUserId, 10)) {
            showMembersModal.value = false;
            currentRoomId.value = null;
            currentRoom.value = null;
            roomOpen.value = false;
            messages.value = [];
        } else {
            currentRoom.value = room;
        }
        await loadRooms();
    } catch (err) {
        notifyError(err.response?.data?.message || getLang('send_failed'));
    }
}

function startFallbackPolling() {
    if (fallbackPollTimer) return;
    fallbackPollTimer = setInterval(() => {
        chatApi.sendHeartbeat().finally(loadRooms);
    }, pollingFallbackMs);
}

function stopFallbackPolling() {
    if (!fallbackPollTimer) return;
    clearInterval(fallbackPollTimer);
    fallbackPollTimer = null;
}

watch(roomSearch, () => {
    clearTimeout(roomSearchTimer);
    roomSearchTimer = setTimeout(loadRooms, 300);
});
watch(roomFilter, () => loadRooms());
watch(messageSearch, () => {
    clearTimeout(roomSearchTimer);
    roomSearchTimer = setTimeout(() => {
        if (currentRoomId.value) loadMessages(currentRoomId.value);
    }, 300);
});

onMounted(async () => {
    unregisterRealtime = realtime?.register?.({
        onMessage: handleMessage,
        onTyping: handleTyping,
        onConnected: handleConnected,
        onDisconnected: handleDisconnected,
    });

    await loadColleagues();
    await loadRooms();

    if (realtime?.isRealtimeEnabled?.()) {
        if (!realtime.connected?.value) {
            setTimeout(() => {
                if (!realtime.connected?.value) startFallbackPolling();
            }, 5000);
        }
    } else {
        startFallbackPolling();
    }
});

onUnmounted(() => {
    unregisterRealtime?.();
    stopFallbackPolling();
    clearTimeout(typingClearTimer);
    clearTimeout(roomSearchTimer);
});
</script>

<template>
    <div class="chat-shell" :class="{ 'room-open': roomOpen }">
        <div class="chat-sidebar">
            <div class="comm-card">
                <div class="comm-card-header">
                    <h3 class="comm-card-title">{{ getLang('chat') }}</h3>
                    <div>
                        <button type="button" class="comm-btn comm-btn-ghost btn-sm" :title="getLang('new_direct_chat')" @click="showDirectModal = true">
                            <i class="fa fa-user-plus"></i>
                        </button>
                        <button type="button" class="comm-btn comm-btn-primary btn-sm" @click="showGroupModal = true">
                            <i class="fa fa-users"></i> {{ getLang('new_group') }}
                        </button>
                    </div>
                </div>
                <div style="padding: 12px 14px 0;">
                    <input v-model="roomSearch" type="text" class="comm-input" :placeholder="getLang('search_chats')">
                    <div class="comm-tabs" style="margin-top:10px;">
                        <button type="button" class="comm-tab" :class="{ active: roomFilter === 'all' }" @click="roomFilter = 'all'">{{ getLang('filter_all') }}</button>
                        <button type="button" class="comm-tab" :class="{ active: roomFilter === 'direct' }" @click="roomFilter = 'direct'">{{ getLang('filter_direct') }}</button>
                        <button type="button" class="comm-tab" :class="{ active: roomFilter === 'group' }" @click="roomFilter = 'group'">{{ getLang('filter_group') }}</button>
                    </div>
                </div>
                <div id="room-list">
                    <div v-if="!rooms.length" class="comm-empty">
                        <i class="fa fa-comments-o"></i>
                        <p>{{ getLang('no_rooms') }}</p>
                    </div>
                    <div
                        v-for="room in rooms"
                        :key="room.id"
                        class="room-item"
                        :class="{ active: currentRoomId === room.id }"
                        @click="selectRoom(room)"
                    >
                        <div class="room-item-inner">
                            <div class="comm-avatar comm-avatar-sm">
                                {{ initials(roomDisplayName(room)) }}
                                <span v-if="room.type === 'direct' && isOtherOnline(room)" class="comm-online-dot"></span>
                            </div>
                            <div class="room-item-body">
                                <div class="room-item-top">
                                    <span class="room-item-name">{{ roomDisplayName(room) }}</span>
                                    <small class="text-muted">{{ formatTime((room.latest_message || {}).created_at || room.last_message_at) }}</small>
                                </div>
                                <div class="room-item-bottom">
                                    <small class="room-item-preview">{{ roomPreview(room) }}</small>
                                    <span v-if="room.unread_count > 0" class="comm-badge">{{ room.unread_count }}</span>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>

        <div class="chat-main">
            <div class="comm-card chat-panel">
                <div class="comm-card-header chat-panel-header">
                    <div style="display:flex;align-items:center;gap:12px;">
                        <button type="button" class="chat-back-btn" :title="getLang('go_back', 'Back')" @click="closeRoom">
                            <i class="fa fa-arrow-right"></i>
                        </button>
                        <div class="comm-avatar">{{ currentRoom ? initials(roomDisplayName(currentRoom)) : '?' }}</div>
                        <div>
                            <h3 class="comm-card-title">{{ currentRoom ? roomDisplayName(currentRoom) : getLang('select_chat') }}</h3>
                            <small class="text-muted">{{ chatSubtitle }}</small>
                        </div>
                    </div>
                    <div class="chat-header-tools">
                        <input
                            v-if="currentRoomId"
                            v-model="messageSearch"
                            type="text"
                            class="comm-input"
                            :placeholder="getLang('search_messages')"
                        >
                        <button
                            v-if="currentRoom?.type === 'group'"
                            type="button"
                            class="comm-btn comm-btn-ghost btn-sm"
                            @click="openMembersModal"
                        >
                            <i class="fa fa-users"></i>
                        </button>
                    </div>
                </div>
                <div class="chat-body">
                    <div class="chat-typing-line" :class="{ visible: !!typingText }">{{ typingText }}</div>
                    <div id="chat-box" ref="messageBox">
                        <div v-if="!messages.length" class="comm-empty">
                            <i class="fa fa-comment-o"></i>
                            <p>{{ currentRoomId ? getLang('no_messages') : getLang('select_chat') }}</p>
                        </div>
                        <div
                            v-for="msg in messages"
                            :key="msg.id || `tmp-${msg.created_at}-${msg.user_id}`"
                            class="chat-msg"
                            :class="parseInt(msg.user_id, 10) === parseInt(currentUserId, 10) ? 'mine' : 'other'"
                        >
                            <div class="chat-bubble">
                                <div v-if="showMessageName(msg)" class="chat-bubble-name">
                                    {{ messageLabel(msg) }}
                                </div>
                                <div class="chat-bubble-body">{{ msg.body }}</div>
                                <div class="chat-bubble-time">{{ formatTime(msg.created_at) }}</div>
                            </div>
                        </div>
                    </div>
                    <div class="chat-composer">
                        <ChatComposer
                            ref="composerRef"
                            v-model="composerText"
                            :disabled="!currentRoomId"
                            :sending="sending"
                            :placeholder="getLang('type_message')"
                            @submit="onSubmitMessage"
                            @typing="onComposerTyping"
                        />
                    </div>
                </div>
            </div>
        </div>

        <!-- Direct chat modal -->
        <div v-if="showDirectModal" class="modal fade in" style="display:block;" @click.self="showDirectModal = false">
            <div class="modal-dialog">
                <div class="modal-content" style="border-radius:14px;">
                    <div class="modal-header">
                        <button type="button" class="close" @click="showDirectModal = false">&times;</button>
                        <h4 class="modal-title">{{ getLang('new_direct_chat') }}</h4>
                    </div>
                    <form @submit.prevent="createDirectRoom">
                        <div class="modal-body">
                            <select v-model="directUserId" class="form-control" required>
                                <option value="">{{ getLang('select_colleague') }}</option>
                                <option v-for="u in colleagues" :key="u.id" :value="u.id">
                                    {{ colleagueLabel(u) }}
                                </option>
                            </select>
                        </div>
                        <div class="modal-footer">
                            <button type="button" class="btn btn-default" @click="showDirectModal = false">{{ getLang('cancel', 'Cancel') }}</button>
                            <button type="submit" class="comm-btn comm-btn-primary">{{ getLang('start_chat') }}</button>
                        </div>
                    </form>
                </div>
            </div>
        </div>

        <!-- Group modal -->
        <div v-if="showGroupModal" class="modal fade in" style="display:block;" @click.self="showGroupModal = false">
            <div class="modal-dialog">
                <div class="modal-content" style="border-radius:14px;">
                    <div class="modal-header">
                        <button type="button" class="close" @click="showGroupModal = false">&times;</button>
                        <h4 class="modal-title">{{ getLang('new_group') }}</h4>
                    </div>
                    <form @submit.prevent="createGroupRoom">
                        <div class="modal-body">
                            <div class="form-group">
                                <label>{{ getLang('group_name') }}</label>
                                <input v-model="groupName" type="text" class="comm-input" required>
                            </div>
                            <div class="form-group">
                                <label>{{ getLang('group_members') }}</label>
                                <select v-model="groupMemberIds" class="form-control" multiple required>
                                    <option v-for="u in colleagues" :key="u.id" :value="u.id">{{ colleagueLabel(u).replace(' ●', '') }}</option>
                                </select>
                            </div>
                        </div>
                        <div class="modal-footer">
                            <button type="button" class="btn btn-default" @click="showGroupModal = false">{{ getLang('cancel', 'Cancel') }}</button>
                            <button type="submit" class="comm-btn comm-btn-primary">{{ getLang('create_group') }}</button>
                        </div>
                    </form>
                </div>
            </div>
        </div>

        <!-- Members modal -->
        <div v-if="showMembersModal" class="modal fade in" style="display:block;" @click.self="showMembersModal = false">
            <div class="modal-dialog">
                <div class="modal-content" style="border-radius:14px;">
                    <div class="modal-header">
                        <button type="button" class="close" @click="showMembersModal = false">&times;</button>
                        <h4 class="modal-title">{{ getLang('group_members') }}</h4>
                    </div>
                    <div class="modal-body">
                        <ul class="list-group">
                            <li
                                v-for="m in (currentRoom?.members || [])"
                                :key="m.id"
                                class="list-group-item"
                                style="display:flex;justify-content:space-between;align-items:center;"
                            >
                                <span>
                                    {{ fullName(m) }}
                                    <span v-if="m.is_online" class="comm-chip comm-chip-active">{{ getLang('online') }}</span>
                                </span>
                                <button
                                    v-if="canManageMembers && m.id !== currentUserId"
                                    type="button"
                                    class="comm-btn comm-btn-danger btn-xs"
                                    @click="removeMember(m.id)"
                                >{{ getLang('remove') }}</button>
                                <button
                                    v-else-if="m.id === currentUserId && currentRoom?.type === 'group'"
                                    type="button"
                                    class="comm-btn comm-btn-danger btn-xs"
                                    @click="removeMember(m.id)"
                                >{{ getLang('leave_group') }}</button>
                            </li>
                        </ul>
                        <hr v-if="canManageMembers">
                        <div v-if="canManageMembers">
                            <label>{{ getLang('add_member') }}</label>
                            <div class="input-group">
                                <select v-model="addMemberUserId" class="form-control">
                                    <option value="">-</option>
                                    <option v-for="u in availableColleaguesForAdd" :key="u.id" :value="u.id">{{ fullName(u) }}</option>
                                </select>
                                <span class="input-group-btn">
                                    <button type="button" class="comm-btn comm-btn-primary" @click="addMember">{{ getLang('add') }}</button>
                                </span>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
        <div v-if="showDirectModal || showGroupModal || showMembersModal" class="modal-backdrop fade in"></div>
    </div>
</template>

<style scoped>
.chat-shell {
    flex: 1 1 auto;
    min-height: 0;
}
</style>
