<script setup lang="ts">
import { Head, usePage } from "@inertiajs/vue3"
import AppLayout from "@/layouts/AppLayout.vue"
import { ref, onMounted, nextTick, computed, watch } from "vue"
import axios from "axios"

import { Badge } from "@/components/ui/badge"
import { ScrollArea } from "@/components/ui/scroll-area"
import { Textarea } from "@/components/ui/textarea"
import { Check, CheckCheck, Paperclip, Send, X } from "lucide-vue-next"
import type {BreadcrumbItem} from "@/types";
import {Toaster} from '@/components/ui/sonner';
import {toast} from 'vue-sonner';

/* ================= TYPES ================= */

interface ChatUser {
    id: number
    name: string
    unread_count: number
    last_seen?: string
    is_online: boolean
}

interface ChatMessage {
    id: number
    user_id: number
    receiver_id: number
    message: string
    file_path?: string | null
    is_read: boolean
    created_at: string
}

/* ================= PROPS ================= */

const props = defineProps<{ users: ChatUser[] }>()

/* ================= STATE ================= */
const breadcrumbs: BreadcrumbItem[] = [{ title: 'Панель управления', href: '/dashboard' },{ title: "Чат", href: "/chat" }];
const authUser = usePage().props.auth.user as { id: number }

const users = ref(props.users)
const selectedUser = ref<ChatUser | null>(null)
const messages = ref<ChatMessage[]>([])

const newMessage = ref("")
const fileInput = ref<HTMLInputElement | null>(null)
const file = ref<File | null>(null)

const isTyping = ref(false)
let typingTimeout: any = null

let loading = false

/* ================= HELPERS ================= */

function openFilePicker() {
    fileInput.value?.click()
}

function onFileChange(e: Event) {
    const target = e.target as HTMLInputElement
    if (!target.files?.length) return

    file.value = target.files[0]
}

function scrollToBottom() {
    const el = document.querySelector(".messages")
    if (el) el.scrollTop = el.scrollHeight
}

function formatTime(date: string) {
    return new Date(date).toLocaleTimeString("ru-RU", {
        hour: "2-digit",
        minute: "2-digit",
    })
}

function formatLastSeen(date: string) {
    return new Date(date).toLocaleString("ru-RU", {
        day: "2-digit",
        month: "2-digit",
        year: "numeric",
        hour: "2-digit",
        minute: "2-digit",
    })
}

function formatDate(date: string) {
    return new Date(date).toLocaleDateString("ru-RU")
}

function isMine(m: ChatMessage) {
    return m.user_id === authUser.id
}

/* ================= GROUPING ================= */

const groupedMessages = computed(() => {
    const groups: Record<string, ChatMessage[]> = {}

    messages.value.forEach(m => {
        const day = formatDate(m.created_at)
        if (!groups[day]) groups[day] = []
        groups[day].push(m)
    })

    return groups
})

/* ================= API ================= */

async function loadMessages(user: ChatUser) {
    selectedUser.value = user

    const { data } = await axios.get(`/chat/${user.id}`)
    messages.value = data

    await nextTick()
    scrollToBottom()
}

async function sendMessage() {
    if (!selectedUser.value) return
    if (!newMessage.value.trim() && !file.value) return

    const formData = new FormData()
    formData.append("receiver_id", selectedUser.value.id.toString())

    if (newMessage.value)
        formData.append("message", newMessage.value)

    if (file.value)
        formData.append("file", file.value)

    const res = await axios.post("/chat", formData)

    messages.value.push(res.data)

    newMessage.value = ""
    file.value = null

    await nextTick()
    scrollToBottom()
}

async function sendTyping() {
    if (!selectedUser.value) return

    await axios.post("/chat/typing", {
        receiver_id: selectedUser.value.id,
    })
}

async function checkTyping() {
    if (!selectedUser.value) return

    const { data } = await axios.get(`/chat/typing/${selectedUser.value.id}`)
    isTyping.value = data.typing
}

async function refreshUsers() {
    try {
        const {data} = await axios.get<ChatUser[]>("/chat/users");

        users.value = users.value.map(u => {
            const server = data.find(d => d.id === u.id);

            if (!server) return u;

            return {
                ...u,
                is_online: Boolean(server.is_online),
                last_seen: server.last_seen,
                unread_count: server.unread_count,
            };
        });

    } catch (e) {
        console.error("refreshUsers error", e);
    }
}

async function checkNewMessages() {
    if (!selectedUser.value) return;

    try {
        const lastId = messages.value.at(-1)?.id ?? 0;

        const { data } = await axios.get(
            `/chat/${selectedUser.value.id}?after=${lastId}`
        );

        if (!data.length) return;

        const existing = new Set(messages.value.map(m => m.id));
        const fresh = data.filter(m => !existing.has(m.id));

        if (fresh.length) {
            messages.value.push(...fresh);

            await nextTick();
            scrollToBottom();
        }

    } catch (e) {
        console.error("checkNewMessages error", e);
    }
}

async function pollMessages() {
    if (loading || !selectedUser.value) return
    loading = true

    try {
        const lastId = messages.value.at(-1)?.id ?? 0

        const { data } = await axios.get(
            `/chat/${selectedUser.value.id}?after=${lastId}`
        )

        const existingIds = new Set(messages.value.map(m => m.id))
        const newMessages = data.filter(m => !existingIds.has(m.id))

        if (newMessages.length) {
            messages.value.push(...newMessages)

            newMessages.forEach(m => {
                if (m.user_id === authUser.id) return

                const sender = users.value.find(u => u.id === m.user_id)

                const chatIsOpen =
                    selectedUser.value?.id === m.user_id

                const shouldNotify =
                    !chatIsOpen || document.hidden || !document.hasFocus()

                if (shouldNotify) {
                    toast("Новое сообщение", {
                        description: `${sender?.name ?? 'Пользователь'}: ${m.message || '📎 Файл'}`,
                    })
                }
            })

            await nextTick()
            scrollToBottom()
        }
    } catch (e) {
        console.error("pollMessages error", e)
    } finally {
        loading = false
    }
}

/* ================= WATCH ================= */

watch(newMessage, () => {
    sendTyping()

    clearTimeout(typingTimeout)
    typingTimeout = setTimeout(() => {}, 1000)
})

/* ================= LIFECYCLE ================= */

onMounted(() => {
    setInterval(pollMessages, 2000)
    setInterval(checkTyping, 2000)
    setInterval(refreshUsers, 5000);
})

function handleEnter(e: KeyboardEvent) {
    // Shift + Enter = новая строка
    if (e.shiftKey) {
        return
    }

    sendMessage()
}
</script>

<template>
    <Head title="Чат" />

    <AppLayout :breadcrumbs="breadcrumbs">
        <div class="flex h-[100dvh] md:h-[calc(100vh-80px)] bg-background md:rounded-xl overflow-hidden">

            <!-- USERS -->
            <div class="w-full md:w-80 border-r flex flex-col" :class="selectedUser ? 'hidden md:flex' : 'flex'">
                <div class="p-4 font-semibold">Чаты</div>

                <ScrollArea class="flex-1">
                    <div
                        v-for="u in users"
                        :key="u.id"
                        @click="loadMessages(u)"
                        class="flex items-center gap-3 p-3 cursor-pointer hover:bg-muted"
                        :class="{ 'bg-muted': selectedUser?.id === u.id }"
                    >
                        <div class="relative">
                            <div class="w-10 h-10 rounded-full bg-gray-400 flex items-center justify-center text-white">
                                {{ u.name[0] }}
                            </div>

                            <span
                                class="absolute bottom-0 right-0 w-3 h-3 rounded-full border-2 border-white"
                                :class="u.is_online ? 'bg-green-500' : 'bg-gray-400'"
                            />
                        </div>

                        <div class="flex-1">
                            <div class="text-sm font-medium">{{ u.name }}</div>
                        </div>

                        <Badge v-if="u.unread_count">
                            {{ u.unread_count }}
                        </Badge>
                    </div>
                </ScrollArea>
            </div>

            <!-- CHAT -->
            <div
                class="flex-1 flex flex-col w-full"
                :class="selectedUser ? 'flex' : 'hidden md:flex'"
            >

                <!-- HEADER -->
                <div
                    v-if="selectedUser"
                    class="p-3 md:p-4 border-b flex justify-between items-center bg-background sticky top-0 z-10"
                >
                    <button
                        class="md:hidden text-muted-foreground"
                        @click="selectedUser = null"
                    >
                        ←
                    </button>
                    <div>
                        <div class="font-semibold">{{ selectedUser.name }}</div>
                        <div class="text-xs text-muted-foreground">
                            <span v-if="selectedUser.is_online">
                                Онлайн
                            </span>
                            <span v-else>
                                Был(а) в сети: {{ selectedUser.last_seen ? formatLastSeen(selectedUser.last_seen) : 'давно' }}
                            </span>
                        </div>
                    </div>
                </div>

                <!-- EMPTY -->
                <div v-if="!selectedUser" class="m-auto text-muted-foreground">
                    Выберите чат
                </div>

                <!-- MESSAGES -->
                <div
                    v-else
                    class="flex-1 overflow-y-auto px-3 md:px-4 py-2 md:py-3 space-y-4 messages"
                >
                    <div v-for="(group, date) in groupedMessages" :key="date">

                        <div class="text-center text-xs text-muted-foreground my-2">
                            {{ date }}
                        </div>

                        <div
                            v-for="m in group"
                            :key="m.id"
                            class="flex p-2"
                            :class="isMine(m) ? 'justify-end' : 'justify-start'"
                        >
                            <div
                                class="max-w-[75%] md:max-w-xs px-3 py-2 rounded-2xl text-sm shadow"
                                :class="isMine(m)
                            ? 'bg-blue-500 text-white rounded-br-none'
                            : 'bg-muted rounded-bl-none'"
                            >
                                <!-- TEXT -->
                                <div v-if="m.message">{{ m.message }}</div>

                                <!-- FILE -->
                                <div v-if="m.file_path" class="mt-2">
                                    <img
                                        v-if="m.file_path.match(/\.(jpg|jpeg|png|webp)$/)"
                                        :src="`/storage/${m.file_path}`"
                                        class="rounded-lg max-w-xs"
                                    />

                                    <a
                                        v-else
                                        :href="`/storage/${m.file_path}`"
                                        target="_blank"
                                        class="text-blue-500 underline text-sm"
                                    >
                                        Скачать файл
                                    </a>
                                </div>

                                <!-- META -->
                                <div class="flex justify-end items-center gap-1 text-xs mt-1 opacity-70">
                                    {{ formatTime(m.created_at) }}

                                    <template v-if="isMine(m)">
                                        <CheckCheck v-if="m.is_read" class="w-3 h-3" />
                                        <Check v-else class="w-3 h-3" />
                                    </template>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>

                <!-- TYPING -->
                <div v-if="isTyping" class="text-xs text-muted-foreground px-4 pt-2 pb-2">
                    Печатает...
                </div>

                <!-- INPUT -->
                <div v-if="selectedUser" class="border-t p-2 md:p-3 pb-[calc(env(safe-area-inset-bottom)+8px)]">

                    <!-- FILE PREVIEW -->
                    <div v-if="file" class="flex items-center justify-between mb-2 bg-muted p-2 rounded-lg text-sm">
                        <span class="flex items-center gap-1 truncate max-w-[80%]">
                            <Paperclip class="h-4" /> {{ file.name }}
                        </span>

                        <button @click="file = null" class="text-red-500 hover:text-red-600 cursor-pointer">
                            <X class="w-4 h-4" />
                        </button>
                    </div>

                    <!-- INPUT ROW -->
                    <form @submit.prevent="sendMessage" class="relative">

                        <!-- TEXTAREA -->
                        <Textarea
                            v-model="newMessage"
                            placeholder="Сообщение..."
                            rows="2"
                            class="w-full pl-11 pr-12 py-3 resize-none rounded-2xl min-h-[44px] chat-input focus-visible:ring-0 focus-visible:ring-offset-0"
                            @keydown.enter.prevent="handleEnter"
                        />

                        <!-- 📎 PAPERCLIP -->
                        <button
                            type="button"
                            @click="openFilePicker"
                            class="absolute left-2 top-1/2 -translate-y-1/2 p-1.5 rounded-full hover:bg-muted transition cursor-pointer"
                        >
                            <Paperclip class="w-5 h-5 text-muted-foreground" />
                        </button>

                        <!-- ➤ SEND -->
                        <button
                            type="submit"
                            class="absolute right-2 top-1/2 -translate-y-1/2 cursor-pointer w-9 h-9 flex items-center justify-center rounded-full bg-blue-500 text-white hover:bg-blue-600 transition shadow"
                        >
                            <Send class="w-4 h-4" />
                        </button>

                        <!-- HIDDEN INPUT -->
                        <input
                            ref="fileInput"
                            type="file"
                            class="hidden"
                            accept="image/*"
                            @change="onFileChange"
                        />
                    </form>
                </div>

            </div>
        </div>
    </AppLayout>
</template>

<style scoped>
.messages {
    scroll-behavior: smooth;
}
.chat-input {
    font-family: 'Inter', sans-serif;
    font-size: 14px;
}
</style>

