import React, { useRef, useEffect } from "react";
import { renderHook, act } from "@testing-library/react";
import { describe, it, expect, vi } from "vitest";
import { useAttachments } from "../use-attachments";

describe("useAttachments", () => {
  // -----------------------------------------------------------------------
  // Referential stability — callbacks must not change between renders
  // -----------------------------------------------------------------------

  describe("referential stability", () => {
    it("all callbacks are stable across re-renders with same config", () => {
      const config = { enabled: true, accept: "image/*" };
      const { result, rerender } = renderHook(() => useAttachments({ config }));

      const first = result.current;
      rerender();
      const second = result.current;

      expect(second.processFiles).toBe(first.processFiles);
      expect(second.handleFileUpload).toBe(first.handleFileUpload);
      expect(second.handleDragOver).toBe(first.handleDragOver);
      expect(second.handleDragLeave).toBe(first.handleDragLeave);
      expect(second.handleDrop).toBe(first.handleDrop);
      expect(second.removeAttachment).toBe(first.removeAttachment);
      expect(second.consumeAttachments).toBe(first.consumeAttachments);
    });

    it("callbacks remain stable when config object reference changes", () => {
      let config = { enabled: true, accept: "image/*" };
      const { result, rerender } = renderHook(() => useAttachments({ config }));

      const first = result.current;

      // Create a new config with same values — different reference
      config = { enabled: true, accept: "image/*" };
      rerender();
      const second = result.current;

      expect(second.processFiles).toBe(first.processFiles);
      expect(second.handleFileUpload).toBe(first.handleFileUpload);
      expect(second.handleDragOver).toBe(first.handleDragOver);
      expect(second.handleDragLeave).toBe(first.handleDragLeave);
      expect(second.handleDrop).toBe(first.handleDrop);
      expect(second.removeAttachment).toBe(first.removeAttachment);
      expect(second.consumeAttachments).toBe(first.consumeAttachments);
    });

    it("refs are stable across re-renders", () => {
      const { result, rerender } = renderHook(() =>
        useAttachments({ config: undefined }),
      );

      const first = result.current;
      rerender();
      const second = result.current;

      expect(second.fileInputRef).toBe(first.fileInputRef);
      expect(second.containerRef).toBe(first.containerRef);
    });
  });

  // -----------------------------------------------------------------------
  // Re-render counting — hook should not cause unnecessary renders
  // -----------------------------------------------------------------------

  describe("re-render counting", () => {
    it("does not re-render when consumeAttachments is called on empty queue", () => {
      let renderCount = 0;

      const { result } = renderHook(() => {
        renderCount++;
        return useAttachments({ config: undefined });
      });

      const initialRenderCount = renderCount;

      act(() => {
        result.current.consumeAttachments();
      });

      // consumeAttachments on empty queue should not trigger a state update
      expect(renderCount).toBe(initialRenderCount);
    });

    it("does not re-render on repeated consumeAttachments with empty queue", () => {
      let renderCount = 0;

      const { result } = renderHook(() => {
        renderCount++;
        return useAttachments({ config: undefined });
      });

      const initialRenderCount = renderCount;

      act(() => {
        result.current.consumeAttachments();
        result.current.consumeAttachments();
        result.current.consumeAttachments();
      });

      expect(renderCount).toBe(initialRenderCount);
    });
  });

  // -----------------------------------------------------------------------
  // State defaults
  // -----------------------------------------------------------------------

  describe("initial state", () => {
    it("returns empty attachments and disabled by default", () => {
      const { result } = renderHook(() =>
        useAttachments({ config: undefined }),
      );

      expect(result.current.attachments).toEqual([]);
      expect(result.current.enabled).toBe(false);
      expect(result.current.dragOver).toBe(false);
    });

    it("returns enabled when config.enabled is true", () => {
      const { result } = renderHook(() =>
        useAttachments({ config: { enabled: true } }),
      );

      expect(result.current.enabled).toBe(true);
    });
  });

  // -----------------------------------------------------------------------
  // consumeAttachments behavior
  // -----------------------------------------------------------------------

  describe("consumeAttachments", () => {
    it("returns empty array when no attachments", () => {
      const { result } = renderHook(() =>
        useAttachments({ config: undefined }),
      );

      let consumed: any[];
      act(() => {
        consumed = result.current.consumeAttachments();
      });

      expect(consumed!).toEqual([]);
    });
  });

  // -----------------------------------------------------------------------
  // removeAttachment
  // -----------------------------------------------------------------------

  describe("removeAttachment", () => {
    it("is a no-op when id does not exist", () => {
      const { result } = renderHook(() =>
        useAttachments({ config: undefined }),
      );

      const before = result.current.attachments;

      act(() => {
        result.current.removeAttachment("nonexistent");
      });

      // Should still be empty, no crash
      expect(result.current.attachments).toEqual([]);
    });
  });
});
