import { openDB } from "idb";
import { useCallback, useEffect, useState } from "react";
import { chatApi } from "../api/chat";

const DB_NAME = "nexus-offline";
const STORE = "message_queue";

interface QueueEntry {
  conversationId: string;
  content: string;
  queuedAt: number;
}

async function getDb() {
  return openDB(DB_NAME, 1, {
    upgrade(db) {
      db.createObjectStore(STORE, { autoIncrement: true });
    },
  });
}

/**
 * Offline message queue backed by IndexedDB.
 * Enqueues messages when offline; auto-flushes when the online event fires.
 */
export function useOfflineQueue(): {
  enqueue: (conversationId: string, content: string) => Promise<void>;
  flush: () => Promise<void>;
  queuedCount: number;
} {
  const [queuedCount, setQueuedCount] = useState(0);

  // On mount, read current queue count from IndexedDB
  useEffect(() => {
    let cancelled = false;
    getDb()
      .then((db) => db.count(STORE))
      .then((count) => {
        if (!cancelled) setQueuedCount(count);
      })
      .catch(() => {
        // IndexedDB unavailable (SSR or private browsing edge case) — ignore
      });
    return () => {
      cancelled = true;
    };
  }, []);

  const flush = useCallback(async () => {
    let db;
    try {
      db = await getDb();
    } catch {
      return;
    }

    const allKeys = await db.getAllKeys(STORE);
    for (const key of allKeys) {
      const entry = (await db.get(STORE, key)) as QueueEntry | undefined;
      if (!entry) continue;
      try {
        await chatApi.postMessage(entry.conversationId, {
          role: "user",
          content: entry.content,
        });
        await db.delete(STORE, key);
        setQueuedCount((c) => Math.max(0, c - 1));
      } catch {
        // Stop flushing on first failure — retry next time the online event fires
        break;
      }
    }
  }, []);

  const enqueue = useCallback(
    async (conversationId: string, content: string) => {
      let db;
      try {
        db = await getDb();
      } catch {
        return;
      }
      await db.add(STORE, { conversationId, content, queuedAt: Date.now() });
      setQueuedCount((c) => c + 1);
    },
    [],
  );

  // Auto-flush when reconnected
  useEffect(() => {
    window.addEventListener("online", flush);
    return () => window.removeEventListener("online", flush);
  }, [flush]);

  return { enqueue, flush, queuedCount };
}
