<template>
  <div class="flex flex-col flex-grow">
    <!-- Список сообщений -->
    <div class="flex-grow overflow-y-auto p-4" ref="messagesContainer">
      <div
        v-for="message in messages"
        :key="message._id"
        class="mb-4 max-w-md"
        :class="{ 'ml-auto': message.from === userRole, 'mr-auto': message.from !== userRole }"
      >
        <Card
          class="p-card-sm"
          :class="{
            'bg-blue-50 border-blue-300 text-blue-500': message.from === userRole,
            'bg-gray-50 border-gray-300 text-gray-700': message.from !== userRole,
          }"
        >
          <template #content>
            {{ message.body }}
          </template>
        </Card>
      </div>

      <slot name="endOfMessages" :count="messages.length"></slot>
    </div>

    <!-- Форма отправки сообщений -->
    <form @submit.prevent="sendMessage" class="flex gap-2 items-center p-4" ref="form">
      <InputText
        id="newMessage"
        v-model="newMessage"
        class="flex-1"
        placeholder="Напишите сообщение"
      />
      <Button type="submit" icon="pi pi-send" class="p-button-md" :disabled="!newMessage.trim()" />
    </form>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted, onUnmounted, useTemplateRef, watch, nextTick } from 'vue'
import { messagesDbLocal as db, messagesDbRemote as remoteDb } from '@/api/dbs'
import { type MessageDocument } from '@/types/DBDocumentTypes'

const formRef = useTemplateRef('form')
const messagesContainerRef = useTemplateRef('messagesContainer')

const { qr_code_uri, chat, userRole } = defineProps<{
  qr_code_uri: MessageDocument['qr_code_uri']
  chat: MessageDocument['chat']
  userRole: MessageDocument['from']
}>()

// Локальные состояния
const messages = ref<MessageDocument[]>([])
const newMessage = ref('')
let changesSubscription: PouchDB.Core.Changes<MessageDocument> | null = null
let syncHandler: PouchDB.Replication.Sync<MessageDocument> | null = null

// Селектор для фильтрации сообщений
const messageSelector = {
  type: 'message',
  qr_code_uri,
  chat,
}

// Загрузка сообщений
async function loadMessages() {
  try {
    const result = await db.find({
      selector: messageSelector,
    })
    messages.value = result.docs as MessageDocument[]
  } catch (error) {
    console.error('Ошибка загрузки сообщений:', error)
  }
}

// Отправка нового сообщения
async function sendMessage() {
  const created_at = new Date().toISOString()
  const message: MessageDocument = {
    _id: `message:${qr_code_uri}:${chat}:${created_at}`,
    type: 'message',
    qr_code_uri,
    chat,
    created_at,
    from: userRole,
    body: newMessage.value.trim(),
  }

  try {
    await db.put(message)
    newMessage.value = ''
  } catch (error) {
    console.error('Ошибка отправки сообщения:', error)
  }
}

// Отслеживание изменений
function watchChanges() {
  changesSubscription = db
    .changes({
      since: 'now',
      live: true,
      include_docs: true,
      selector: messageSelector,
    })
    .on('change', (change: { doc?: MessageDocument }) => {
      if (change.doc) {
        const index = messages.value.findIndex((m) => m._id === change.doc!._id)
        if (index === -1) {
          // Если сообщения нет, добавляем его
          messages.value.push(change.doc)
        } else {
          // Если сообщение существует, обновляем его
          messages.value[index] = change.doc
        }
        // Сортируем массив сообщений
        messages.value.sort((a, b) => (a.created_at > b.created_at ? 1 : -1))
      }
    })
    .on('error', (err) => {
      console.error('Ошибка отслеживания изменений:', err)
    })
}

// Настройка синхронизации
function setupSync() {
  syncHandler = db.sync(remoteDb, {
    live: true,
    retry: true,
    selector: messageSelector,
  })
  syncHandler.on('error', (err) => {
    console.error('Ошибка синхронизации:', err)
  })
}

// Остановка синхронизации
function stopSync() {
  if (syncHandler) {
    syncHandler.cancel()
    syncHandler = null
  }
}

// Отписка от изменений
function stopWatchingChanges() {
  if (changesSubscription) {
    changesSubscription.cancel()
    changesSubscription = null
  }
}

// Логика жизненного цикла
onMounted(async () => {
  watchChanges()
  setupSync()
  await loadMessages()
  formRef.value?.querySelector('input')?.focus()
})

watch(
  () => messages.value?.length,
  async () => {
    if (messagesContainerRef.value) {
      await nextTick()
      messagesContainerRef.value.scrollTop = messagesContainerRef.value.scrollHeight
    }
  },
)

onUnmounted(() => {
  stopWatchingChanges()
  stopSync()
})
</script>

<style scoped>
/* Чат занимает всё доступное пространство */
.flex-grow {
  display: flex;
  flex-direction: column;
  flex-grow: 1;
}

.overflow-y-auto {
  overflow-y: auto;
  height: 0;
  flex-grow: 1;
}
</style>
