/**
 * Solicita permissão para notificações desktop
 */
export async function requestNotificationPermission(): Promise<NotificationPermission> {
  if (!("Notification" in window)) {
    console.warn("Este navegador não suporta notificações desktop");
    return "denied";
  }

  if (Notification.permission === "granted") {
    return "granted";
  }

  if (Notification.permission !== "denied") {
    return await Notification.requestPermission();
  }

  return Notification.permission;
}

/**
 * Mostra uma notificação desktop
 */
export function showNotification(title: string, options?: NotificationOptions): Notification | null {
  if (!("Notification" in window)) {
    return null;
  }

  if (Notification.permission !== "granted") {
    return null;
  }

  try {
    return new Notification(title, {
      icon: "/favicon.png",
      badge: "/favicon.png",
      ...options,
    });
  } catch (error) {
    console.error("Erro ao exibir notificação:", error);
    return null;
  }
}

/**
 * Toca o som de notificação
 */
export function playNotificationSound() {
  try {
    const audio = new Audio("/sounds/notification.mp3");
    audio.volume = 0.5;
    audio.play().catch((err) => {
      console.warn("Não foi possível reproduzir o som de notificação:", err);
    });
  } catch (error) {
    console.error("Erro ao tocar som de notificação:", error);
  }
}

/**
 * Verifica se o usuário está na aba ativa
 */
export function isTabActive(): boolean {
  return !document.hidden;
}

/**
 * Registrar service worker para push notifications
 */
export async function registrarServiceWorker(): Promise<ServiceWorkerRegistration | null> {
  if (!("serviceWorker" in navigator)) {
    console.warn("Service Workers não são suportados neste navegador");
    return null;
  }

  try {
    // Verificar se já existe um Service Worker ativo antes de registrar
    const existingRegistration = await navigator.serviceWorker.getRegistration("/");
    if (existingRegistration?.active) {
      return existingRegistration;
    }

    // Registrar com timeout para evitar travamentos
    const registerPromise = navigator.serviceWorker.register("/sw.js", {
      scope: "/",
    });

    const timeoutPromise = new Promise<ServiceWorkerRegistration | null>((resolve) =>
      setTimeout(() => resolve(null), 3000)
    );

    const registration = await Promise.race([registerPromise, timeoutPromise]);
    
    if (registration) {
      // Log apenas em desenvolvimento
      if (import.meta.env.DEV) {
        console.log("Service Worker registrado:", registration);
      }
    }
    
    return registration;
  } catch (error) {
    // Ignorar erros silenciosamente para evitar spam no console
    // especialmente erros relacionados a message channel
    if (error instanceof Error) {
      const errorMessage = error.message.toLowerCase();
      if (
        !errorMessage.includes("message channel") &&
        !errorMessage.includes("registration") &&
        import.meta.env.DEV
      ) {
        console.error("Erro ao registrar Service Worker:", error);
      }
    }
    return null;
  }
}

/**
 * Solicitar subscription de push notification
 */
export async function solicitarPushSubscription(): Promise<PushSubscription | null> {
  try {
    // Registrar service worker primeiro com timeout
    const registrationPromise = registrarServiceWorker();
    const timeoutPromise = new Promise<null>((resolve) => 
      setTimeout(() => resolve(null), 3000)
    );
    
    const registration = await Promise.race([registrationPromise, timeoutPromise]);
    if (!registration) {
      return null;
    }

    // Verificar se push está disponível
    if (!("PushManager" in window)) {
      return null;
    }

    // Solicitar permissão com timeout
    const permissionPromise = requestNotificationPermission();
    const permissionTimeoutPromise = new Promise<NotificationPermission>((resolve) =>
      setTimeout(() => resolve("denied"), 3000)
    );
    
    const permission = await Promise.race([permissionPromise, permissionTimeoutPromise]);
    if (permission !== "granted") {
      return null;
    }

    // Obter subscription existente ou criar nova com timeout
    const getSubscriptionPromise = registration.pushManager.getSubscription();
    const getSubscriptionTimeoutPromise = new Promise<PushSubscription | null>((resolve) =>
      setTimeout(() => resolve(null), 3000)
    );
    
    let subscription = await Promise.race([getSubscriptionPromise, getSubscriptionTimeoutPromise]);

    if (!subscription) {
      // VAPID public key deve vir do backend ou config
      const vapidPublicKey = import.meta.env.VITE_VAPID_PUBLIC_KEY || "";

      if (!vapidPublicKey) {
        // Não logar warning para evitar spam no console
        return null;
      }

      // Converter chave para formato Uint8Array
      const applicationServerKey = urlBase64ToUint8Array(vapidPublicKey);

      // Subscribe com timeout
      const subscribePromise = registration.pushManager.subscribe({
        userVisibleOnly: true,
        applicationServerKey,
      });
      
      const subscribeTimeoutPromise = new Promise<PushSubscription | null>((resolve) =>
        setTimeout(() => resolve(null), 5000)
      );
      
      subscription = await Promise.race([subscribePromise, subscribeTimeoutPromise]);
    }

    return subscription;
  } catch (error) {
    // Ignorar erros relacionados a message channel ou service worker
    if (error instanceof Error) {
      const errorMessage = error.message.toLowerCase();
      if (
        errorMessage.includes("message channel") ||
        errorMessage.includes("service worker") ||
        errorMessage.includes("registration")
      ) {
        return null;
      }
    }
    return null;
  }
}

/**
 * Converter chave VAPID de base64 URL-safe para Uint8Array
 */
function urlBase64ToUint8Array(base64String: string): Uint8Array {
  const padding = "=".repeat((4 - (base64String.length % 4)) % 4);
  const base64 = (base64String + padding).replace(/-/g, "+").replace(/_/g, "/");

  const rawData = window.atob(base64);
  const outputArray = new Uint8Array(rawData.length);

  for (let i = 0; i < rawData.length; ++i) {
    outputArray[i] = rawData.charCodeAt(i);
  }
  return outputArray;
}

/**
 * Converter PushSubscription para formato serializável
 */
export function subscriptionToJSON(subscription: PushSubscription): {
  endpoint: string;
  keys: { p256dh: string; auth: string };
} {
  const key = subscription.getKey("p256dh");
  const auth = subscription.getKey("auth");

  if (!key || !auth) {
    throw new Error("Chaves de subscription não encontradas");
  }

  return {
    endpoint: subscription.endpoint,
    keys: {
      p256dh: arrayBufferToBase64(key),
      auth: arrayBufferToBase64(auth),
    },
  };
}

/**
 * Converter ArrayBuffer para base64
 */
function arrayBufferToBase64(buffer: ArrayBuffer): string {
  const bytes = new Uint8Array(buffer);
  let binary = "";
  for (let i = 0; i < bytes.byteLength; i++) {
    binary += String.fromCharCode(bytes[i]);
  }
  return window.btoa(binary);
}

/**
 * Remover subscription de push notification
 */
export async function removerPushSubscription(): Promise<boolean> {
  const registration = await navigator.serviceWorker.ready;
  const subscription = await registration.pushManager.getSubscription();

  if (subscription) {
    await subscription.unsubscribe();
    return true;
  }

  return false;
}

