import { defineStore } from "pinia";
import { ref } from "vue";
import { getCurrentUser, getUnreadCount } from "@/lib/api";
import { getWsUrl } from "@/lib/utils";
import { toast } from "vue-sonner";

export const useAuthStore = defineStore("auth", () => {
  const user = ref<any>(null);
  const isLoading = ref(true);
  const showCompleteProfile = ref(false);
  let initialized = false;
  const wsAuthFailed = ref(false);

  async function refreshUser() {
    try {
      const userData = await getCurrentUser();
      user.value = userData;
      wsAuthFailed.value = false; // Reset on successful auth
      showCompleteProfile.value = !!(
        userData && (!userData.phone || !userData.shipping_address)
      );
    } catch {
      user.value = null;
      showCompleteProfile.value = false;
      stopPing();
    } finally {
      isLoading.value = false;
      if (user.value && !pingInterval && !wsAuthFailed.value) startPing();
    }
  }

  let pingInterval: number | null = null;
  const unreadMessagesCount = ref(0);

  let globalWs: WebSocket | null = null;
  let reconnectTimer: number | null = null;

  // ── Audio ──────────────────────────────────────────────────────────────────
  // Single shared AudioContext, created lazily on first user gesture.
  let sharedAudioCtx: AudioContext | null = null;

  function getAudioCtx(): AudioContext | null {
    const AudioCtx = window.AudioContext || (window as any).webkitAudioContext;
    if (!AudioCtx) return null;
    if (!sharedAudioCtx) sharedAudioCtx = new AudioCtx();
    return sharedAudioCtx;
  }

  // Unlock AudioContext as soon as the user interacts with the page
  function unlockAudio() {
    const ctx = getAudioCtx();
    if (ctx && ctx.state === 'suspended') ctx.resume().catch(() => {});
  }
  window.addEventListener('click',   unlockAudio, { passive: true });
  window.addEventListener('keydown', unlockAudio, { passive: true });
  window.addEventListener('touchstart', unlockAudio, { passive: true });

  async function playUpdateSound() {
    try {
      const ctx = getAudioCtx();
      if (!ctx) return;
      if (ctx.state === 'suspended') await ctx.resume();

      const osc = ctx.createOscillator();
      const gainNode = ctx.createGain();

      osc.type = 'sine';
      osc.frequency.setValueAtTime(180, ctx.currentTime);
      osc.frequency.exponentialRampToValueAtTime(140, ctx.currentTime + 0.3);

      gainNode.gain.setValueAtTime(0, ctx.currentTime);
      gainNode.gain.linearRampToValueAtTime(0.15, ctx.currentTime + 0.05);
      gainNode.gain.linearRampToValueAtTime(0, ctx.currentTime + 0.35);

      osc.connect(gainNode);
      gainNode.connect(ctx.destination);
      osc.start();
      osc.stop(ctx.currentTime + 0.35);
    } catch (e) {
      console.warn("Audio update sound error", e);
    }
  }

  async function playNotificationSound() {
    try {
      const ctx = getAudioCtx();
      if (!ctx) return;
      if (ctx.state === 'suspended') await ctx.resume();

      const osc = ctx.createOscillator();
      const gainNode = ctx.createGain();
      
      osc.type = 'sine';
      osc.frequency.setValueAtTime(880, ctx.currentTime); // A5
      osc.frequency.exponentialRampToValueAtTime(1760, ctx.currentTime + 0.1); // Up to A6
      
      gainNode.gain.setValueAtTime(0, ctx.currentTime);
      gainNode.gain.linearRampToValueAtTime(0.1, ctx.currentTime + 0.05);
      gainNode.gain.linearRampToValueAtTime(0, ctx.currentTime + 0.2);
      
      osc.connect(gainNode);
      gainNode.connect(ctx.destination);
      osc.start();
      osc.stop(ctx.currentTime + 0.2);
    } catch (e) {
      console.warn("Audio notification sound error", e);
    }
  }

  async function playChatSound() {
    try {
      const ctx = getAudioCtx();
      if (!ctx) return;
      if (ctx.state === 'suspended') await ctx.resume();

      const osc = ctx.createOscillator();
      const gainNode = ctx.createGain();
      
      osc.type = "sine";
      osc.frequency.setValueAtTime(880, ctx.currentTime);
      osc.frequency.exponentialRampToValueAtTime(440, ctx.currentTime + 0.1);
      
      gainNode.gain.setValueAtTime(0, ctx.currentTime);
      gainNode.gain.linearRampToValueAtTime(0.3, ctx.currentTime + 0.05);
      gainNode.gain.exponentialRampToValueAtTime(0.01, ctx.currentTime + 0.3);
      
      osc.connect(gainNode);
      gainNode.connect(ctx.destination);
      
      osc.start();
      osc.stop(ctx.currentTime + 0.3);
    } catch (e) {
      console.warn("Audio chat sound error", e);
    }
  }
  // ───────────────────────────────────────────────────────────────────────────

  function startPing() {
    stopPing(); // Ensure fresh start
    const token = localStorage.getItem("token");
    if (!token || wsAuthFailed.value) return;
    const url = `${getWsUrl()}/global?token=${encodeURIComponent(token)}`;
    globalWs = new WebSocket(url);

    globalWs.onopen = () => {
      // Send ping every 25 seconds to keep connection alive and update online status in Redis
      pingInterval = window.setInterval(() => {
        if (globalWs && globalWs.readyState === WebSocket.OPEN) {
          globalWs.send("ping");
        }
      }, 25000);
    };

    globalWs.onmessage = (event) => {
      try {
        const msg = JSON.parse(event.data);
        if (msg.type === "unread_count" && msg.count !== undefined) {
          if (msg.count > unreadMessagesCount.value) {
            playNotificationSound();
          }
          unreadMessagesCount.value = msg.count;
        } else if (msg.type === "new_chat_message") {
          toast(`Message for Order #${msg.order_id}`, {
            description: msg.text,
            action: {
              label: "View",
              onClick: () => {
                window.location.href = `/admin?order=${msg.order_id}`;
              }
            }
          });
        } else if (msg.type === "account_suspended") {
          toast.error("Your account has been suspended by an administrator.", { duration: 10000 });
          logout();
        } else if (msg.type === "order_read") {
          window.dispatchEvent(new CustomEvent("radionica:order_read", { detail: { order_id: msg.order_id } }));
        } else if (msg.type === "order_updated") {
          playUpdateSound();
          window.dispatchEvent(new CustomEvent("radionica:order_updated", { detail: { order_id: msg.order_id } }));
        }
      } catch (e) {
        console.error("WS Parse error", e);
      }
    };


    globalWs.onclose = (event) => {
      if (pingInterval) clearInterval(pingInterval);
      
      // 4001: Auth fail, 4003: Suspended, 1008: Policy
      if (event.code === 4001 || event.code === 1008 || event.code === 4003) {
        console.warn(`WS Connection terminated (code ${event.code}).`);
        wsAuthFailed.value = true;
        if (event.code === 4003) {
          user.value = null; // Instant clear
          localStorage.removeItem("token");
        }
        return;
      }

      if (user.value) { 
        // If still logged in, try reconnecting. 
        // We only don't reconnect if wsAuthFailed is set during onclose for specific codes.
        if (!wsAuthFailed.value) {
          reconnectTimer = window.setTimeout(startPing, 5000);
        }
      }
    };

    globalWs.onerror = () => {
      // On error, the close event will follow
      console.error("WS Connection error occurred");
    };
  }

  function stopPing() {
    if (pingInterval) {
      clearInterval(pingInterval);
      pingInterval = null;
    }
    if (reconnectTimer) {
      clearTimeout(reconnectTimer);
      reconnectTimer = null;
    }
    if (globalWs) {
      globalWs.onclose = null; // Disable auto reconnect
      globalWs.onerror = null;
      globalWs.close();
      globalWs = null;
    }
  }

  let initPromise: Promise<void> | null = null;

  function init(): Promise<void> {
    if (!initPromise) {
      initPromise = refreshUser();
    }
    return initPromise;
  }

  function setUser(u: any) {
    user.value = u;
    wsAuthFailed.value = false;
    if (u && !pingInterval) startPing();
  }

  function onProfileComplete() {
    showCompleteProfile.value = false;
    refreshUser();
  }

  async function logout() {
    const { logoutUser } = await import("@/lib/api");
    try {
      await logoutUser();
    } catch (e) {
      console.error("Logout API call failed, continuing local cleanup", e);
    }
    localStorage.removeItem("token");
    user.value = null;
    unreadMessagesCount.value = 0;
    stopPing();
  }

  async function refreshUnreadCount() {
    try {
      const { count } = await getUnreadCount();
      unreadMessagesCount.value = count;
    } catch (e) {
      console.error("Failed to refresh unread count", e);
    }
  }

  return {
    user,
    isLoading,
    showCompleteProfile,
    unreadMessagesCount,
    init,
    setUser,
    refreshUser,
    onProfileComplete,
    logout,
    refreshUnreadCount,
    playChatSound
  };
});
