<template>
  <div class="place-self-stretch flex flex-col">
    <div
      v-for="message in messages"
      :key="message._id"
      :id="`msg-${message.created_at}`"
      class="mb-4 max-w-md"
      :class="{
        'ml-auto text-right': message.from === userRole,
        'mr-auto text-left': message.from !== userRole,
      }"
    >
      <Card
        class="p-card-sm"
        :class="{
          'bg-blue-50 dark:bg-blue-900 border-blue-300 dark:border-blue-700 text-blue-500 dark:text-blue-200':
            message.from === userRole,
          'bg-gray-50 dark:bg-gray-800 border-gray-300 dark:border-gray-700 text-gray-700 dark:text-gray-300':
            message.from !== userRole,
        }"
      >
        <template #content>
          {{ message.body }}
        </template>
      </Card>
    </div>

    <slot
      name="endOfMessages"
      :count="messages.length"
      :lastMessage="messages.length > 0 ? messages[messages.length - 1] : null"
    />
  </div>
</template>

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

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

// Локальные состояния
const messages = ref<MessageDocument[]>([])

let changesSubscription: PouchDB.Core.Changes<MessageDocument> | null = null
let syncMessages: 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,
      limit: Number.MAX_SAFE_INTEGER,
    })
    messages.value = result.docs as MessageDocument[]
  } 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() {
  syncMessages = db.sync(remoteDb, {
    live: true,
    retry: true,
    selector: messageSelector,
  })
  syncMessages.on('error', (err) => {
    console.error('Ошибка синхронизации:', err)
  })
}

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

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

// Логика жизненного цикла
onMounted(async () => {
  watchChanges()
  setupSync()
  await loadMessages()
})

const emit = defineEmits<{
  (event: 'scrollToBottom'): void
}>()

watch(
  () => messages.value?.length,
  async () => {
    await nextTick()
    emit('scrollToBottom')
  },
)

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>
