<script setup lang="ts">
import type { SupportConversation } from "~/types";

definePageMeta({
  middleware: "auth"
});

const { user, token } = useAuth();
const { formatDateTime } = useBrowserDateTime();
const { connect, disconnect, onConversationUpdated, onMessageCreated } = useSupportRealtime();
const { replaceConversations, upsertConversation } = useSupportUnread();

const conversations = ref<SupportConversation[]>([]);
const activeConversationId = ref<string | null>(null);
const conversation = ref<SupportConversation | null>(null);
const loading = ref(false);
const sending = ref(false);
const statusSaving = ref(false);
const draft = ref("");
const errorMessage = ref("");
const messageListRef = ref<HTMLElement | null>(null);
const isMobile = ref(false);

const isAdmin = computed(() => user.value?.role === "admin");
const showAdminConversation = computed(() => !isAdmin.value || !isMobile.value || Boolean(activeConversationId.value));
const showAdminList = computed(() => isAdmin.value && (!isMobile.value || !activeConversationId.value));

const activeConversation = computed(() => {
  if (!isAdmin.value) {
    return conversation.value;
  }

  return conversations.value.find((item) => item.id === activeConversationId.value) ?? conversation.value;
});

const canSend = computed(() => draft.value.trim().length > 0 && !sending.value);

const sortConversations = (items: SupportConversation[]) =>
  [...items].sort((left, right) => new Date(right.lastMessageAt).getTime() - new Date(left.lastMessageAt).getTime());

const updateConversationInList = (nextConversation: SupportConversation) => {
  const withoutCurrent = conversations.value.filter((item) => item.id !== nextConversation.id);
  conversations.value = sortConversations([nextConversation, ...withoutCurrent]);
};

const replaceActiveConversation = (nextConversation: SupportConversation) => {
  conversation.value = nextConversation;
  updateConversationInList(nextConversation);

  if (!activeConversationId.value) {
    activeConversationId.value = nextConversation.id;
  }
};

const scrollToBottom = async () => {
  await nextTick();

  if (!messageListRef.value) {
    return;
  }

  messageListRef.value.scrollTop = messageListRef.value.scrollHeight;
};

const loadUserConversation = async () => {
  loading.value = true;

  try {
    const response = await useChatApi<SupportConversation>("/support/conversation");
    conversation.value = response;
    activeConversationId.value = response.id;
    conversations.value = [response];
    replaceConversations([response]);
    errorMessage.value = "";
    await scrollToBottom();
  } catch (error) {
    errorMessage.value = error instanceof Error ? error.message : "Не удалось загрузить чат";
  } finally {
    loading.value = false;
  }
};

const loadAdminConversations = async () => {
  loading.value = true;

  try {
    const response = await useChatApi<SupportConversation[]>("/admin/support/conversations");
    conversations.value = sortConversations(response);
    replaceConversations(response);

    if (!activeConversationId.value && response.length > 0) {
      activeConversationId.value = response[0].id;
    }

    if (activeConversationId.value) {
      await loadAdminConversation(activeConversationId.value);
    } else {
      conversation.value = null;
    }

    errorMessage.value = "";
  } catch (error) {
    errorMessage.value = error instanceof Error ? error.message : "Не удалось загрузить обращения";
  } finally {
    loading.value = false;
  }
};

const loadAdminConversation = async (conversationId: string) => {
  activeConversationId.value = conversationId;

  try {
    const response = await useChatApi<SupportConversation>(`/admin/support/conversations/${conversationId}`);
    replaceActiveConversation(response);
    upsertConversation(response);
    errorMessage.value = "";
    await scrollToBottom();
  } catch (error) {
    errorMessage.value = error instanceof Error ? error.message : "Не удалось открыть диалог";
  }
};

const closeMobileConversation = () => {
  if (!isAdmin.value || !isMobile.value) {
    return;
  }

  activeConversationId.value = null;
  conversation.value = null;
};

const loadPage = async () => {
  if (isAdmin.value) {
    await loadAdminConversations();
    return;
  }

  await loadUserConversation();
};

const sendMessage = async () => {
  const body = draft.value.trim();
  if (!body) {
    return;
  }

  sending.value = true;

  try {
    const response = isAdmin.value
      ? await useChatApi<SupportConversation>(`/admin/support/conversations/${activeConversationId.value}/messages`, {
          method: "POST",
          body: {
            body
          }
        })
      : await useChatApi<SupportConversation>("/support/conversation/messages", {
          method: "POST",
          body: {
            body
          }
        });

    draft.value = "";
    replaceActiveConversation(response);
    upsertConversation(response);
    errorMessage.value = "";
    await scrollToBottom();
  } catch (error) {
    errorMessage.value = error instanceof Error ? error.message : "Не удалось отправить сообщение";
  } finally {
    sending.value = false;
  }
};

const setConversationStatus = async (status: "open" | "closed") => {
  if (!isAdmin.value || !activeConversationId.value) {
    return;
  }

  statusSaving.value = true;

  try {
    const response = await useChatApi<SupportConversation>(`/admin/support/conversations/${activeConversationId.value}`, {
      method: "PATCH",
      body: {
        status
      }
    });

    replaceActiveConversation(response);
    upsertConversation(response);
    errorMessage.value = "";
  } catch (error) {
    errorMessage.value = error instanceof Error ? error.message : "Не удалось обновить статус";
  } finally {
    statusSaving.value = false;
  }
};

const handleRealtimeConversation = async (payload: { conversation: SupportConversation }) => {
  if (!payload?.conversation) {
    return;
  }

  updateConversationInList(payload.conversation);
  upsertConversation(payload.conversation);

  if (!isAdmin.value) {
    conversation.value = payload.conversation;
    await scrollToBottom();
    return;
  }

  if (!activeConversationId.value) {
    activeConversationId.value = payload.conversation.id;
  }

  if (payload.conversation.id === activeConversationId.value) {
    conversation.value = payload.conversation;
    await scrollToBottom();
  }
};

const handleRealtimeMessage = async (payload: { conversation: SupportConversation }) => {
  await handleRealtimeConversation(payload);
};

let offConversationUpdated: (() => void) | null = null;
let offMessageCreated: (() => void) | null = null;

onMounted(async () => {
  if (process.client) {
    const mediaQuery = window.matchMedia("(max-width: 767px)");
    const syncIsMobile = () => {
      isMobile.value = mediaQuery.matches;
    };

    syncIsMobile();
    mediaQuery.addEventListener("change", syncIsMobile);
    onBeforeUnmount(() => {
      mediaQuery.removeEventListener("change", syncIsMobile);
    });
  }

  await loadPage();

  if (!process.client || !token.value) {
    return;
  }

  connect();
  offConversationUpdated = onConversationUpdated((payload) => {
    void handleRealtimeConversation(payload);
  });
  offMessageCreated = onMessageCreated((payload) => {
    void handleRealtimeMessage(payload);
  });
});

onBeforeUnmount(() => {
  offConversationUpdated?.();
  offConversationUpdated = null;
  offMessageCreated?.();
  offMessageCreated = null;
  disconnect();
});

watch(
  () => activeConversation.value?.messages?.length,
  () => {
    void scrollToBottom();
  }
);
</script>

<template>
  <section class="page admin-grid">
    <div class="page-header page-header--admin-section">
      <div>
        <h2>{{ isAdmin ? "Обращения пользователей" : "Чат с поддержкой" }}</h2>
        <p class="muted">
          {{
            isAdmin
              ? "Все администраторы видят единый поток обращений и могут отвечать пользователям прямо из приложения."
              : "Напишите админу прямо здесь. Когда поддержка ответит, сообщение появится в этом чате."
          }}
        </p>
      </div>
    </div>

    <p v-if="errorMessage" class="error">{{ errorMessage }}</p>

    <div
      class="grid gap-4"
      :style="isAdmin && !isMobile ? { gridTemplateColumns: 'minmax(280px, 360px) minmax(0, 1fr)' } : undefined"
    >
      <div v-if="showAdminList" class="panel" style="padding: 0;">
        <div class="admin-list" style="padding: 1rem;">
          <div
            v-for="item in conversations"
            :key="item.id"
            class="rounded-2xl border p-4 transition cursor-pointer"
            :style="{
              borderColor: item.id === activeConversationId ? 'var(--accent)' : 'var(--border)',
              backgroundColor: item.id === activeConversationId ? 'color-mix(in srgb, var(--accent) 8%, var(--surface))' : 'var(--surface)'
            }"
            @click="loadAdminConversation(item.id)"
          >
            <div class="flex items-start justify-between gap-3">
              <div class="min-w-0">
                <strong class="block truncate">{{ item.user.email }}</strong>
                <span class="text-sm text-(--muted)">
                  {{ item.status === "closed" ? "Закрыт" : item.unreadForAdmin ? "Новое сообщение" : "Открыт" }}
                </span>
              </div>
              <span
                v-if="item.unreadForAdmin"
                class="signal-row__badge signal-row__badge--win"
              >
                новое
              </span>
            </div>
            <p class="mt-3 mb-1 text-sm break-words">
              {{ item.latestMessage?.body || "Пока без сообщений" }}
            </p>
            <p class="m-0 text-xs text-(--muted)">
              {{ formatDateTime(item.lastMessageAt) }}
            </p>
          </div>
          <p v-if="!conversations.length && !loading" class="muted">Обращений пока нет.</p>
        </div>
      </div>

      <div v-if="showAdminConversation" class="panel">
        <div
          v-if="activeConversation"
          class="grid gap-4"
          :style="{ minHeight: isAdmin ? '70vh' : '60vh', gridTemplateRows: 'auto minmax(0, 1fr) auto' }"
        >
          <div class="flex flex-wrap items-center justify-between gap-3">
            <div class="flex items-center gap-3">
              <button
                v-if="isAdmin && isMobile"
                type="button"
                class="secondary"
                style="padding-inline: 0.85rem;"
                @click="closeMobileConversation"
              >
                Назад
              </button>

              <div>
              <strong class="block">
                {{ isAdmin ? activeConversation.user.email : "Поддержка" }}
              </strong>
              <span class="text-sm text-(--muted)">
                {{
                  activeConversation.status === "closed"
                    ? "Диалог закрыт"
                    : isAdmin
                      ? "Отвечайте пользователю от лица поддержки"
                      : "Админы ответят сюда же"
                }}
              </span>
              </div>
            </div>

            <div v-if="isAdmin" class="flex gap-2">
              <button
                class="secondary"
                :disabled="statusSaving || activeConversation.status === 'open'"
                @click="setConversationStatus('open')"
              >
                Открыть
              </button>
              <button
                :disabled="statusSaving || activeConversation.status === 'closed'"
                @click="setConversationStatus('closed')"
              >
                Закрыть
              </button>
            </div>
          </div>

          <div
            ref="messageListRef"
            class="grid gap-3 overflow-y-auto rounded-2xl border p-3"
            :style="{ borderColor: 'var(--border)', backgroundColor: 'var(--surface)' }"
          >
            <div
              v-for="message in activeConversation.messages ?? []"
              :key="message.id"
              class="flex"
              :style="{ justifyContent: message.author.id === user?.id ? 'flex-end' : 'flex-start' }"
            >
              <div
                class="max-w-[85%] rounded-2xl px-4 py-3"
                :style="message.author.id === user?.id
                  ? {
                      backgroundColor: 'color-mix(in srgb, var(--accent) 18%, var(--surface))',
                      border: '1px solid color-mix(in srgb, var(--accent) 35%, var(--border))'
                    }
                  : {
                      backgroundColor: 'var(--surface-strong)',
                      border: '1px solid var(--border)'
                    }"
              >
                <div class="mb-2 text-xs text-(--muted)">
                  {{ message.author.email }} · {{ formatDateTime(message.createdAt) }}
                </div>
                <div class="whitespace-pre-wrap break-words">{{ message.body }}</div>
              </div>
            </div>

            <p v-if="!(activeConversation.messages ?? []).length" class="muted">
              {{ isAdmin ? "В этом диалоге ещё нет сообщений." : "Напишите первое сообщение админу." }}
            </p>
          </div>

          <form class="grid gap-3" @submit.prevent="sendMessage">
            <textarea
              v-model="draft"
              rows="4"
              placeholder="Введите сообщение"
              :disabled="activeConversation.status === 'closed' && !isAdmin"
            />
            <div class="flex items-center justify-between gap-3">
              <span class="text-sm text-(--muted)">
                {{
                  activeConversation.status === "closed"
                    ? isAdmin
                      ? "Диалог закрыт, но администратор может открыть его снова."
                      : "Диалог закрыт. Дождитесь, пока администратор откроет его снова."
                    : "Сообщения доставляются в реальном времени."
                }}
              </span>
              <button
                type="submit"
                :disabled="!canSend || (!isAdmin && activeConversation.status === 'closed')"
              >
                {{ sending ? "Отправка..." : "Отправить" }}
              </button>
            </div>
          </form>
        </div>

        <div v-else-if="loading" class="muted">Загрузка чата...</div>
        <div v-else class="muted">
          {{ isAdmin ? "Выберите диалог слева или дождитесь нового обращения." : "Чат пока недоступен." }}
        </div>
      </div>
    </div>
  </section>
</template>
