<script setup>
const toast = useToast()
const { $api } = useNuxtApp()

const status = ref(null)
const identity = ref(null)
const matrixRooms = ref([])
const activeRoomKey = ref("allgemein")
const matrixMessages = ref([])
const matrixMembers = ref([])
const matrixMessageDraft = ref("")
const matrixMessagesViewport = ref(null)
const roomCreateOpen = ref(false)
const roomCreateForm = ref({
  name: "",
  key: "",
  topic: ""
})
const loading = ref(false)
const roomProvisioning = ref(false)
const roomCreating = ref(false)
const roomMembersSyncing = ref(false)
const matrixMessagesLoading = ref(false)
const matrixMembersLoading = ref(false)
const matrixMessageSending = ref(false)
const matrixAutoRefreshActive = ref(false)
const lastUpdated = ref(null)
let matrixRefreshInterval = null
let matrixMessagesRequestActive = false
let matrixMembersRequestActive = false

const canUseMatrixChat = computed(() =>
  Boolean(status.value?.reachable && status.value?.provisioningConfigured)
)

const activeRoom = computed(() =>
  matrixRooms.value.find((room) => room.key === activeRoomKey.value) || {
    key: activeRoomKey.value,
    name: activeRoomKey.value,
    description: "Mandantenweiter Austausch",
    exists: false,
    roomId: "",
    unread: 0
  }
)

const activeRoomEndpoint = computed(() =>
  `/api/communication/matrix/rooms/${encodeURIComponent(activeRoomKey.value)}`
)

const roomCreateKeyPreview = computed(() =>
  normalizeRoomKey(roomCreateForm.value.key || roomCreateForm.value.name)
)

const rooms = computed(() => [
  ...matrixRooms.value.map((room) => ({
    ...room,
    description: room.alias || room.roomId || "Mandantenweiter Austausch"
  })),
  {
    key: "projects",
    name: "Projekt-Chats",
    description: "Nächste Ausbaustufe",
    exists: false,
    disabled: true
  },
  {
    key: "direct",
    name: "Direktnachrichten",
    description: "Nächste Ausbaustufe",
    exists: false,
    disabled: true
  }
])

const normalizeRoomKey = (value) => {
  const normalized = String(value || "")
    .toLowerCase()
    .normalize("NFKD")
    .replace(/[\u0300-\u036f]/g, "")
    .replace(/ä/g, "a")
    .replace(/ö/g, "o")
    .replace(/ü/g, "u")
    .replace(/ß/g, "ss")
    .replace(/[^a-z0-9._=-]+/g, "_")
    .replace(/_+/g, "_")
    .replace(/^[._=-]+|[._=-]+$/g, "")

  return normalized || "raum"
}

const setActiveRoom = async (room) => {
  if (room.disabled || room.key === activeRoomKey.value) return

  activeRoomKey.value = room.key
  matrixMessages.value = []
  matrixMembers.value = []
  await loadRoomChat({ includeMembers: true })
}

const upsertRoom = (room) => {
  const roomWasKnown = matrixRooms.value.some((item) => item.key === room.key)
  matrixRooms.value = roomWasKnown
    ? matrixRooms.value.map((item) => item.key === room.key ? { ...item, ...room } : item)
    : [...matrixRooms.value, room]
}

const mergeMatrixMessages = (incomingMessages) => {
  const byId = new Map()

  for (const message of matrixMessages.value) {
    byId.set(message.id, message)
  }

  for (const message of incomingMessages || []) {
    byId.set(message.id, {
      ...byId.get(message.id),
      ...message,
      pending: false,
      failed: false
    })
  }

  matrixMessages.value = Array.from(byId.values())
    .sort((a, b) => (a.timestamp || 0) - (b.timestamp || 0))
}

const scrollMessagesToBottom = async () => {
  await nextTick()
  if (!matrixMessagesViewport.value) return

  matrixMessagesViewport.value.scrollTop = matrixMessagesViewport.value.scrollHeight
}

const loadChatInfo = async () => {
  loading.value = true
  try {
    const [statusRes, identityRes, roomsRes] = await Promise.all([
      $api("/api/communication/matrix/status"),
      $api("/api/communication/matrix/me"),
      $api("/api/communication/matrix/rooms")
    ])

    status.value = statusRes
    identity.value = identityRes
    matrixRooms.value = roomsRes.rooms || []
    lastUpdated.value = new Date()

    if (activeRoom.value?.exists && canUseMatrixChat.value) {
      await loadRoomChat({ silent: true, includeMembers: true })
    }
  } catch (error) {
    toast.add({
      title: "Chat konnte nicht geladen werden",
      color: "error"
    })
  } finally {
    loading.value = false
  }
}

const provisionActiveRoom = async () => {
  roomProvisioning.value = true
  try {
    const res = await $api(`${activeRoomEndpoint.value}/provision`, {
      method: "POST"
    })

    upsertRoom({ ...res, exists: true })

    toast.add({
      title: res.alreadyExisted ? "Chatraum ist bereit" : "Chatraum erstellt",
      color: "success"
    })

    await loadRoomChat({ includeMembers: true })
  } catch (error) {
    toast.add({
      title: "Chatraum konnte nicht erstellt werden",
      color: "error"
    })
  } finally {
    roomProvisioning.value = false
  }
}

const createRoom = async () => {
  const name = roomCreateForm.value.name.trim()
  const key = roomCreateKeyPreview.value
  const topic = roomCreateForm.value.topic.trim()

  if (!name) {
    toast.add({
      title: "Bitte gib einen Raumnamen ein",
      color: "warning"
    })
    return
  }

  roomCreating.value = true
  try {
    const room = await $api("/api/communication/matrix/rooms", {
      method: "POST",
      body: {
        key,
        name,
        topic: topic || undefined,
        type: "room"
      }
    })

    upsertRoom({ ...room, exists: true })
    activeRoomKey.value = room.key
    matrixMessages.value = []
    matrixMembers.value = []
    roomCreateForm.value = {
      name: "",
      key: "",
      topic: ""
    }
    roomCreateOpen.value = false

    toast.add({
      title: room.alreadyExisted ? "Chatraum ist bereit" : "Chatraum erstellt",
      color: "success"
    })

    await loadRoomChat({ includeMembers: true })
  } catch (error) {
    toast.add({
      title: "Chatraum konnte nicht erstellt werden",
      color: "error"
    })
  } finally {
    roomCreating.value = false
  }
}

const loadRoomMessages = async ({ silent = false } = {}) => {
  if (!canUseMatrixChat.value || !activeRoom.value?.exists) return
  if (matrixMessagesRequestActive) return

  matrixMessagesRequestActive = true
  if (!silent) matrixMessagesLoading.value = true

  try {
    const res = await $api(`${activeRoomEndpoint.value}/messages`)
    mergeMatrixMessages(res.messages || [])
    matrixRooms.value = matrixRooms.value.map((room) => room.key === activeRoomKey.value ? {
      ...room,
      alias: res.alias || room.alias,
      exists: true,
      roomId: res.roomId || room.roomId
    } : room)
    await scrollMessagesToBottom()
  } catch (error) {
    if (!silent) {
      toast.add({
        title: "Nachrichten konnten nicht geladen werden",
        color: "error"
      })
    }
  } finally {
    matrixMessagesRequestActive = false
    if (!silent) matrixMessagesLoading.value = false
  }
}

const loadRoomMembers = async ({ silent = false } = {}) => {
  if (!canUseMatrixChat.value || !activeRoom.value?.exists) return
  if (matrixMembersRequestActive) return

  matrixMembersRequestActive = true
  if (!silent) matrixMembersLoading.value = true

  try {
    const res = await $api(`${activeRoomEndpoint.value}/members`)
    matrixMembers.value = res.members || []
  } catch (error) {
    if (!silent) {
      toast.add({
        title: "Teilnehmer konnten nicht geladen werden",
        color: "error"
      })
    }
  } finally {
    matrixMembersRequestActive = false
    if (!silent) matrixMembersLoading.value = false
  }
}

const syncRoomMembers = async () => {
  if (!canUseMatrixChat.value || !activeRoom.value?.exists) return

  roomMembersSyncing.value = true
  try {
    const res = await $api(`${activeRoomEndpoint.value}/members/sync`, {
      method: "POST"
    })

    toast.add({
      title: "Teilnehmer synchronisiert",
      description: `${res.joined || 0} synchronisiert, ${res.failed || 0} fehlgeschlagen`,
      color: res.failed ? "warning" : "success"
    })

    await loadRoomMembers()
  } catch (error) {
    toast.add({
      title: "Teilnehmer konnten nicht synchronisiert werden",
      color: "error"
    })
  } finally {
    roomMembersSyncing.value = false
  }
}

const loadRoomChat = async ({ silent = false, includeMembers = false } = {}) => {
  await loadRoomMessages({ silent })

  if (includeMembers) {
    await loadRoomMembers({ silent })
  }
}

const sendMatrixMessage = async () => {
  const text = matrixMessageDraft.value.trim()
  if (!text || !canUseMatrixChat.value || !activeRoom.value?.exists) return

  const optimisticId = `pending-${Date.now()}`
  const optimisticMessage = {
    id: optimisticId,
    sender: identity.value?.matrixUserId || "Du",
    senderDisplayName: identity.value?.displayName || "Du",
    body: text,
    timestamp: Date.now(),
    own: true,
    pending: true,
    failed: false
  }

  matrixMessages.value = [
    ...matrixMessages.value,
    optimisticMessage
  ]
  matrixMessageDraft.value = ""
  await scrollMessagesToBottom()

  matrixMessageSending.value = true
  try {
    const message = await $api(`${activeRoomEndpoint.value}/messages`, {
      method: "POST",
      body: { text }
    })

    matrixMessages.value = matrixMessages.value.map((item) =>
      item.id === optimisticId ? message : item
    )
  } catch (error) {
    matrixMessages.value = matrixMessages.value.map((item) =>
      item.id === optimisticId ? { ...item, pending: false, failed: true } : item
    )
    toast.add({
      title: "Nachricht konnte nicht gesendet werden",
      color: "error"
    })
  } finally {
    matrixMessageSending.value = false
  }
}

const startMatrixAutoRefresh = () => {
  if (matrixRefreshInterval) return

  matrixAutoRefreshActive.value = true
  matrixRefreshInterval = window.setInterval(() => {
    if (!document.hidden && canUseMatrixChat.value && activeRoom.value?.exists) {
      loadRoomChat({ silent: true })
    }
  }, 15000)
}

const stopMatrixAutoRefresh = () => {
  if (!matrixRefreshInterval) return

  window.clearInterval(matrixRefreshInterval)
  matrixRefreshInterval = null
  matrixAutoRefreshActive.value = false
}

const formatMessageTime = (timestamp) => {
  if (!timestamp) return ""

  return new Intl.DateTimeFormat("de-DE", {
    dateStyle: "short",
    timeStyle: "short"
  }).format(new Date(timestamp))
}

const formatLastUpdated = computed(() => {
  if (!lastUpdated.value) return "Noch nicht aktualisiert"

  return new Intl.DateTimeFormat("de-DE", {
    hour: "2-digit",
    minute: "2-digit"
  }).format(lastUpdated.value)
})

watch(
  () => matrixMessages.value.length,
  () => scrollMessagesToBottom()
)

onMounted(async () => {
  await loadChatInfo()
  startMatrixAutoRefresh()
})

onBeforeUnmount(stopMatrixAutoRefresh)
</script>

<template>
  <div class="flex min-h-0 flex-1 overflow-hidden">
    <aside class="hidden w-72 shrink-0 flex-col border-r border-default bg-default lg:flex">
      <div class="border-b border-default p-4">
        <div class="flex items-center justify-between gap-3">
          <div>
            <h1 class="text-lg font-semibold text-highlighted">
              Chat
            </h1>
            <p class="text-xs text-muted">
              {{ formatLastUpdated }}
            </p>
          </div>
          <UButton
              icon="i-heroicons-arrow-path"
              color="neutral"
              variant="ghost"
              :loading="loading || matrixMessagesLoading"
              :disabled="!canUseMatrixChat"
              @click="loadRoomChat({ includeMembers: true })"
          />
        </div>
      </div>

      <div class="border-b border-default p-3">
        <UButton
            icon="i-heroicons-plus"
            color="primary"
            variant="soft"
            block
            :disabled="!canUseMatrixChat"
            @click="roomCreateOpen = !roomCreateOpen"
        >
          Raum erstellen
        </UButton>

        <form
            v-if="roomCreateOpen"
            class="mt-3 space-y-3 rounded-md border border-default bg-muted p-3"
            @submit.prevent="createRoom"
        >
          <UInput
              v-model="roomCreateForm.name"
              placeholder="Raumname"
              :disabled="roomCreating"
          />
          <UInput
              v-model="roomCreateForm.key"
              placeholder="Raum-Key optional"
              :disabled="roomCreating"
          />
          <UTextarea
              v-model="roomCreateForm.topic"
              placeholder="Thema optional"
              :rows="2"
              :disabled="roomCreating"
          />
          <p class="truncate text-xs text-muted">
            Key: {{ roomCreateKeyPreview }}
          </p>
          <div class="flex justify-end gap-2">
            <UButton
                type="button"
                color="neutral"
                variant="ghost"
                :disabled="roomCreating"
                @click="roomCreateOpen = false"
            >
              Abbrechen
            </UButton>
            <UButton
                type="submit"
                icon="i-heroicons-check"
                :loading="roomCreating"
                :disabled="!roomCreateForm.name.trim()"
            >
              Erstellen
            </UButton>
          </div>
        </form>
      </div>

      <div class="flex-1 overflow-y-auto p-3">
        <button
            v-for="room in rooms"
            :key="room.key"
            type="button"
            class="mb-1 flex w-full items-center gap-3 rounded-md px-3 py-2 text-left transition"
            :class="[
              room.disabled ? 'cursor-not-allowed opacity-50' : 'text-highlighted hover:bg-muted',
              room.key === activeRoomKey ? 'bg-muted ring-1 ring-primary/20' : ''
            ]"
            :disabled="room.disabled"
            @click="setActiveRoom(room)"
        >
          <span class="flex size-9 shrink-0 items-center justify-center rounded-md bg-primary/10 text-primary">
            <UIcon name="i-heroicons-chat-bubble-left-right" class="size-5" />
          </span>
          <span class="min-w-0 flex-1">
            <span class="block truncate text-sm font-medium">{{ room.name }}</span>
            <span class="block truncate text-xs text-muted">{{ room.description }}</span>
          </span>
          <UBadge
              v-if="room.exists"
              color="success"
              variant="soft"
              size="xs"
          >
            aktiv
          </UBadge>
          <UBadge
              v-else-if="!room.disabled"
              color="neutral"
              variant="soft"
              size="xs"
          >
            offen
          </UBadge>
        </button>
      </div>

      <div class="border-t border-default p-3">
        <UButton
            to="/communication"
            icon="i-heroicons-cog-6-tooth"
            color="neutral"
            variant="outline"
            block
        >
          Matrix-Setup
        </UButton>
      </div>
    </aside>

    <main class="flex min-w-0 flex-1 flex-col bg-muted">
      <header class="flex shrink-0 items-center justify-between gap-3 border-b border-default bg-default px-4 py-3">
        <div class="min-w-0">
          <div class="flex items-center gap-2">
            <h2 class="truncate text-base font-semibold text-highlighted">
              {{ activeRoom.name }}
            </h2>
            <UBadge
                v-if="matrixAutoRefreshActive && activeRoom?.exists"
                color="success"
                variant="soft"
                size="xs"
            >
              Live
            </UBadge>
          </div>
          <p class="truncate text-xs text-muted">
            <span v-if="matrixMembers.length">{{ matrixMembers.length }} Teilnehmer</span>
            <span v-else>{{ activeRoom.description }}</span>
          </p>
        </div>

        <div class="flex items-center gap-2">
          <UButton
              class="lg:hidden"
              to="/communication"
              icon="i-heroicons-cog-6-tooth"
              color="neutral"
              variant="outline"
          />
          <UButton
              class="lg:hidden"
              icon="i-heroicons-plus"
              color="primary"
              variant="soft"
              :disabled="!canUseMatrixChat"
              @click="roomCreateOpen = !roomCreateOpen"
          />
          <UButton
              icon="i-heroicons-arrow-path"
              color="neutral"
              variant="outline"
              :loading="matrixMessagesLoading"
              :disabled="!canUseMatrixChat || !activeRoom?.exists"
              @click="loadRoomChat({ includeMembers: true })"
          >
            Laden
          </UButton>
        </div>
      </header>

      <div class="border-b border-default bg-default p-3 lg:hidden">
        <div class="flex gap-2 overflow-x-auto pb-1">
          <button
              v-for="room in rooms"
              :key="room.key"
              type="button"
              class="shrink-0 rounded-md border border-default px-3 py-2 text-left text-sm"
              :class="room.key === activeRoomKey ? 'bg-muted text-highlighted' : 'text-muted'"
              :disabled="room.disabled"
              @click="setActiveRoom(room)"
          >
            {{ room.name }}
          </button>
        </div>

        <form
            v-if="roomCreateOpen"
            class="mt-3 grid gap-2 rounded-md border border-default bg-muted p-3"
            @submit.prevent="createRoom"
        >
          <UInput
              v-model="roomCreateForm.name"
              placeholder="Raumname"
              :disabled="roomCreating"
          />
          <UInput
              v-model="roomCreateForm.key"
              placeholder="Raum-Key optional"
              :disabled="roomCreating"
          />
          <UTextarea
              v-model="roomCreateForm.topic"
              placeholder="Thema optional"
              :rows="2"
              :disabled="roomCreating"
          />
          <p class="truncate text-xs text-muted">
            Key: {{ roomCreateKeyPreview }}
          </p>
          <div class="flex justify-end gap-2">
            <UButton
                type="button"
                color="neutral"
                variant="ghost"
                :disabled="roomCreating"
                @click="roomCreateOpen = false"
            >
              Abbrechen
            </UButton>
            <UButton
                type="submit"
                icon="i-heroicons-check"
                :loading="roomCreating"
                :disabled="!roomCreateForm.name.trim()"
            >
              Erstellen
            </UButton>
          </div>
        </form>
      </div>

      <div
          v-if="status && (!status.reachable || !status.provisioningConfigured)"
          class="border-b border-default bg-default px-4 py-3"
      >
        <UAlert
            icon="i-heroicons-exclamation-triangle"
            color="warning"
            variant="soft"
            title="Matrix ist noch nicht bereit"
            description="Bitte prüfe das Matrix-Setup, bevor der Chat genutzt wird."
        />
      </div>

      <div
          v-else-if="status && !activeRoom?.exists"
          class="border-b border-default bg-default px-4 py-3"
      >
        <UAlert
            icon="i-heroicons-chat-bubble-left-right"
            color="primary"
            variant="soft"
            :title="`${activeRoom.name} ist noch nicht in Matrix angelegt`"
            description="Die Raum-Metadaten sind in FEDEO vorhanden. Lege jetzt den Matrix-Raum dazu an."
        >
          <template #actions>
            <UButton
                icon="i-heroicons-plus"
                :loading="roomProvisioning"
                @click="provisionActiveRoom"
            >
              Matrix-Raum erstellen
            </UButton>
          </template>
        </UAlert>
      </div>

      <div
          ref="matrixMessagesViewport"
          class="min-h-0 flex-1 space-y-3 overflow-y-auto p-4 sm:p-5"
      >
        <div
            v-if="!matrixMessages.length && !matrixMessagesLoading"
            class="flex h-full min-h-64 items-center justify-center text-sm text-muted"
        >
          Noch keine Nachrichten in diesem Chat.
        </div>

        <div
            v-for="message in matrixMessages"
            :key="message.id"
            class="flex"
            :class="message.own ? 'justify-end' : 'justify-start'"
        >
          <div
              class="max-w-[82%] rounded-lg px-3 py-2 shadow-sm sm:max-w-[68%]"
              :class="[
                message.own ? 'bg-primary text-inverted' : 'bg-default text-highlighted',
                message.pending ? 'opacity-70' : '',
                message.failed ? 'bg-error text-inverted' : ''
              ]"
          >
            <div class="mb-1 flex flex-wrap items-center gap-x-2 gap-y-1 text-[11px] opacity-75">
              <span class="truncate font-medium">
                {{ message.own ? "Du" : message.senderDisplayName || message.sender }}
              </span>
              <span>{{ formatMessageTime(message.timestamp) }}</span>
              <span v-if="message.pending">wird gesendet</span>
              <span v-if="message.failed">nicht gesendet</span>
            </div>
            <p class="whitespace-pre-wrap break-words text-sm">
              {{ message.body }}
            </p>
          </div>
        </div>
      </div>

      <form
          class="flex shrink-0 gap-2 border-t border-default bg-default p-3"
          @submit.prevent="sendMatrixMessage"
      >
        <UInput
            v-model="matrixMessageDraft"
            class="min-w-0 flex-1"
            placeholder="Nachricht schreiben"
            :disabled="matrixMessageSending || !canUseMatrixChat || !activeRoom?.exists"
            @keydown.enter.exact.prevent="sendMatrixMessage"
        />
        <UButton
            type="submit"
            icon="i-heroicons-paper-airplane"
            :loading="matrixMessageSending"
            :disabled="!matrixMessageDraft.trim() || !canUseMatrixChat || !activeRoom?.exists"
        >
          Senden
        </UButton>
      </form>
    </main>

    <aside class="hidden w-80 shrink-0 border-l border-default bg-default xl:block">
      <div class="border-b border-default p-4">
        <h3 class="text-sm font-semibold text-highlighted">
          Raumdetails
        </h3>
        <p class="mt-1 break-all font-mono text-xs text-muted">
          {{ activeRoom?.roomId || activeRoom?.alias || "Noch kein Matrix-Raum" }}
        </p>
      </div>

      <div class="space-y-5 p-4">
        <div>
          <div class="mb-2 flex items-center justify-between gap-2">
            <h4 class="text-xs font-medium uppercase text-muted">
              Teilnehmer
            </h4>
            <div class="flex items-center gap-1">
              <UButton
                  icon="i-heroicons-user-plus"
                  color="neutral"
                  variant="ghost"
                  size="xs"
                  :loading="roomMembersSyncing"
                  :disabled="!canUseMatrixChat || !activeRoom?.exists"
                  @click="syncRoomMembers"
              />
              <UButton
                  icon="i-heroicons-arrow-path"
                  color="neutral"
                  variant="ghost"
                  size="xs"
                  :loading="matrixMembersLoading"
                  :disabled="!canUseMatrixChat || !activeRoom?.exists"
                  @click="loadRoomMembers"
              />
            </div>
          </div>

          <div class="space-y-2">
            <div
                v-for="member in matrixMembers"
                :key="member.matrixUserId"
                class="flex items-center gap-2"
            >
              <span class="flex size-8 shrink-0 items-center justify-center rounded-md bg-muted text-xs font-medium text-highlighted">
                {{ (member.displayName || member.matrixUserId || "?").slice(0, 1).toUpperCase() }}
              </span>
              <div class="min-w-0">
                <p class="truncate text-sm font-medium text-highlighted">
                  {{ member.displayName || member.matrixUserId }}
                </p>
                <p class="truncate text-xs text-muted">
                  {{ member.matrixUserId }}
                </p>
              </div>
            </div>

            <p
                v-if="!matrixMembers.length"
                class="text-sm text-muted"
            >
              Noch keine Teilnehmer geladen.
            </p>
          </div>
        </div>

        <div>
          <h4 class="mb-2 text-xs font-medium uppercase text-muted">
            Eigene Identität
          </h4>
          <p class="break-all font-mono text-xs text-highlighted">
            {{ identity?.matrixUserId || "-" }}
          </p>
        </div>
      </div>
    </aside>
  </div>
</template>
