<template>
  <div class="order-chat flex flex-col" :class="compact ? 'h-[320px]' : 'h-[420px]'">
    <!-- Header -->
    <div class="flex items-center justify-between px-4 py-3 border-b border-border/50 bg-card/60 backdrop-blur-sm rounded-t-2xl">
      <div class="flex items-center gap-2">
        <MessageCircle class="w-4 h-4 text-primary" />
        <span class="text-sm font-bold">{{ t("chat.title") }}</span>
        <span class="w-2 h-2 rounded-full" :class="wsConnected ? 'bg-emerald-500' : 'bg-rose-500'" :title="wsConnected ? 'Connected' : 'Disconnected'" />
        <span v-if="otherPartyOnline" class="text-[10px] text-emerald-500 font-bold ml-2 flex items-center gap-1 animate-in fade-in zoom-in duration-300">
          <Eye class="w-3 h-3" /> Online
        </span>
      </div>
      <button v-if="closable" @click="$emit('close')" class="p-1 hover:bg-secondary rounded-lg transition-colors">
        <X class="w-4 h-4 text-muted-foreground" />
      </button>
    </div>

    <!-- Messages area -->
    <div ref="messagesContainer" class="flex-1 overflow-y-auto px-4 py-3 space-y-3 scrollbar-thin">
      <div v-if="isLoading" class="flex items-center justify-center h-full">
        <Loader2 class="w-6 h-6 animate-spin text-primary" />
      </div>

      <div v-else-if="messages.length === 0" class="flex flex-col items-center justify-center h-full text-center opacity-60">
        <MessageCircle class="w-10 h-10 text-muted-foreground mb-3 opacity-40" />
        <p class="text-sm text-muted-foreground">{{ t("chat.empty") }}</p>
      </div>

      <template v-else>
        <div
          v-for="msg in messages"
          :key="msg.id"
          class="flex"
          :class="msg.is_from_admin ? 'justify-start' : 'justify-end'"
        >
          <div
            class="max-w-[80%] px-3.5 py-2 rounded-2xl text-sm leading-relaxed shadow-sm"
            :class="msg.is_from_admin
              ? 'bg-secondary/80 text-foreground rounded-bl-md'
              : 'bg-primary text-primary-foreground rounded-br-md'"
          >
            <div v-if="msg.is_from_admin" class="flex items-center gap-1.5 mb-1">
              <ShieldCheck class="w-3 h-3 opacity-70" />
              <span class="text-[10px] font-bold uppercase tracking-wider opacity-70">{{ t("chat.admin") }}</span>
            </div>
            <p class="whitespace-pre-wrap break-words">{{ msg.message }}</p>
            <p class="text-[10px] mt-1 opacity-50 text-right">{{ formatTime(msg.created_at) }}</p>
          </div>
        </div>
      </template>

      <!-- Typing Indicator -->
      <div v-if="isOtherPartyTyping" class="flex justify-start mb-2 animate-in fade-in zoom-in duration-300">
        <div class="bg-secondary/60 text-muted-foreground px-4 py-3 rounded-2xl rounded-bl-md flex items-center gap-1.5 shadow-sm">
          <span class="w-1.5 h-1.5 bg-foreground/40 rounded-full animate-bounce" style="animation-delay: 0ms"></span>
          <span class="w-1.5 h-1.5 bg-foreground/40 rounded-full animate-bounce" style="animation-delay: 150ms"></span>
          <span class="w-1.5 h-1.5 bg-foreground/40 rounded-full animate-bounce" style="animation-delay: 300ms"></span>
        </div>
      </div>
    </div>

    <!-- Input area -->
    <div class="px-3 py-3 border-t border-border/50 bg-card/40 rounded-b-2xl">
      <form @submit.prevent="handleSend" class="flex gap-2 items-end">
        <textarea
          v-model="newMessage"
          :placeholder="t('chat.placeholder')"
          rows="1"
          class="flex-1 resize-none bg-background/80 border border-border/50 rounded-xl px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-primary/40 transition-all placeholder:text-muted-foreground/50 max-h-[80px] overflow-y-auto"
          @keydown.enter.exact.prevent="handleSend"
          @input="onTextareaInput($event); autoResize($event)"
          ref="textareaRef"
        />
        <button
          type="submit"
          :disabled="!newMessage.trim() || isSending || cooldownLeft > 0"
          class="p-2.5 bg-primary text-primary-foreground rounded-xl hover:bg-primary/90 transition-all disabled:opacity-40 disabled:cursor-not-allowed flex-shrink-0 relative"
        >
          <Send v-if="!isSending && cooldownLeft === 0" class="w-4 h-4" />
          <Loader2 v-else-if="isSending" class="w-4 h-4 animate-spin" />
          <span v-else-if="cooldownLeft > 0" class="text-[10px] font-bold">{{ cooldownLeft }}s</span>
        </button>
      </form>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted, onUnmounted, nextTick, watch } from "vue";
import { useI18n } from "vue-i18n";
import { MessageCircle, Send, Loader2, ShieldCheck, X, Eye } from "lucide-vue-next";
import { getOrderMessages, sendOrderMessage } from "@/lib/api";
import { useAuthStore } from "@/stores/auth";

const WS_BASE_URL = import.meta.env.VITE_WS_URL || "ws://localhost:8000";

const props = defineProps<{
  orderId: number;
  compact?: boolean;
  closable?: boolean;
}>();

defineEmits<{ (e: 'close'): void }>();

const { t, locale } = useI18n();
const messages = ref<any[]>([]);
const newMessage = ref("");
const isLoading = ref(true);
const isSending = ref(false);
const cooldownLeft = ref(0);
const wsConnected = ref(false);
const messagesContainer = ref<HTMLElement | null>(null);
const textareaRef = ref<HTMLTextAreaElement | null>(null);
const otherPartyOnline = ref(false);
const isOtherPartyTyping = ref(false);
let typingTimeout: ReturnType<typeof setTimeout> | null = null;
let cooldownInterval: ReturnType<typeof setInterval> | null = null;

function startCooldown() {
  if (authStore.user?.role === 'admin') return;
  cooldownLeft.value = 10;
  if (cooldownInterval) clearInterval(cooldownInterval);
  cooldownInterval = setInterval(() => {
    cooldownLeft.value--;
    if (cooldownLeft.value <= 0) {
      if (cooldownInterval) clearInterval(cooldownInterval);
    }
  }, 1000);
}
const authStore = useAuthStore();



let ws: WebSocket | null = null;
let reconnectTimer: ReturnType<typeof setTimeout> | null = null;

function connectWebSocket() {
  const token = localStorage.getItem("token");
  if (!token) return;

  ws = new WebSocket(`${WS_BASE_URL}/chat?token=${encodeURIComponent(token)}&order_id=${props.orderId}`);

  ws.onopen = () => {
    wsConnected.value = true;
  };

  ws.onmessage = (event) => {
    try {
      const msg = JSON.parse(event.data);
      if (msg.type === "presence") {
        const myRole = authStore.user?.role === 'admin' ? 'admin' : 'user';
        const otherRole = myRole === 'admin' ? 'user' : 'admin';
        otherPartyOnline.value = msg.online_roles.includes(otherRole);
        return;
      }
      
      if (msg.type === "typing" || msg.type === "stop_typing") {
        const myRole = authStore.user?.role === 'admin' ? 'admin' : 'user';
        const isFromOther = (msg.is_admin && myRole === 'user') || (!msg.is_admin && myRole === 'admin');
        if (isFromOther) {
          isOtherPartyTyping.value = (msg.type === "typing");
          scrollToBottom();
        }
        return;
      }
      
      // If it's a message (type 'message' or has essential fields)
      if (msg.type === "message" || (msg.message && msg.id)) {
        // Use lenient comparison (==) for ID to avoid string/int mismatches
        const exists = messages.value.some(m => m.id == msg.id);
        if (!exists) {
          messages.value.push(msg);
          scrollToBottom();
          
          // Audio & Read Receipt for incoming messages
          const myRole = authStore.user?.role === 'admin' ? 'admin' : 'user';
          const isMsgFromMe = (msg.is_from_admin && myRole === 'admin') || (!msg.is_from_admin && myRole === 'user');
          if (!isMsgFromMe) {
            authStore.playChatSound();
            ws?.send("read");
            setTimeout(() => authStore.refreshUnreadCount(), 300);
          }
        }
      }
    } catch (e) {
      console.error("WS parse error:", e);
    }
  };

  ws.onclose = () => {
    wsConnected.value = false;
    // Auto-reconnect after 3 seconds
    reconnectTimer = setTimeout(() => connectWebSocket(), 3000);
  };

  ws.onerror = () => {
    ws?.close();
  };
}

function disconnectWebSocket() {
  if (reconnectTimer) {
    clearTimeout(reconnectTimer);
    reconnectTimer = null;
  }
  if (ws) {
    ws.onclose = null; // prevent auto-reconnect
    ws.close();
    ws = null;
  }
  wsConnected.value = false;
}

async function loadMessages() {
  try {
    messages.value = await getOrderMessages(props.orderId, locale.value);
    authStore.refreshUnreadCount();
  } catch (e) {
    console.error("Failed to load messages:", e);
  } finally {
    isLoading.value = false;
  }
}

async function handleSend() {
  const text = newMessage.value.trim();
  if (!text || isSending.value) return;

  isSending.value = true;
  try {
    const response = await sendOrderMessage(props.orderId, text, locale.value);
    newMessage.value = "";
    if (textareaRef.value) {
      textareaRef.value.style.height = "auto";
    }
    
    // Add message to list only if it hasn't arrived via WS yet
    if (!messages.value.some(m => m.id == response.id)) {
      const myRole = authStore.user?.role === 'admin' ? 'admin' : 'user';
      messages.value.push({
        id: response.id,
        message: text,
        is_from_admin: myRole === 'admin',
        created_at: new Date().toISOString()
      });
      scrollToBottom();
    }
    
    // Start flood control cooldown
    startCooldown();
  } catch (e) {
    console.error("Failed to send message:", e);
  } finally {
    isSending.value = false;
  }
}

function scrollToBottom() {
  nextTick(() => {
    if (messagesContainer.value) {
      messagesContainer.value.scrollTop = messagesContainer.value.scrollHeight;
    }
  });
}

function autoResize(e: Event) {
  const el = e.target as HTMLTextAreaElement;
  el.style.height = "auto";
  el.style.height = Math.min(el.scrollHeight, 80) + "px";
}

function onTextareaInput(e: Event) {
  if (wsConnected.value && ws) {
    ws.send("typing");
    if (typingTimeout) clearTimeout(typingTimeout);
    typingTimeout = setTimeout(() => {
      if (ws && ws.readyState === WebSocket.OPEN) {
        ws.send("stop_typing");
      }
    }, 2000);
  }
}

function formatTime(dt: string) {
  if (!dt) return "";
  const d = new Date(dt);
  return d.toLocaleString(undefined, { month: "short", day: "numeric", hour: "2-digit", minute: "2-digit" });
}

onMounted(async () => {
  await loadMessages();
  scrollToBottom();
  connectWebSocket();
});

onUnmounted(() => {
  disconnectWebSocket();
});

watch(() => props.orderId, async () => {
  disconnectWebSocket();
  isLoading.value = true;
  await loadMessages();
  scrollToBottom();
  connectWebSocket();
});
</script>

<style scoped>
.scrollbar-thin::-webkit-scrollbar { width: 4px; }
.scrollbar-thin::-webkit-scrollbar-thumb { background: hsl(var(--border)); border-radius: 9999px; }
.scrollbar-thin::-webkit-scrollbar-track { background: transparent; }
</style>
