/**
 * ReadingProgress Component Tests
 *
 * Tests for blog reading progress bar component
 *
 * Test Coverage:
 * - Initial render and mounting
 * - Progress calculation on scroll
 * - Progress bar width updates
 * - Edge cases (0% and 100% progress)
 * - Scroll event listener lifecycle
 * - ARIA attributes and accessibility
 * - Visual styling classes
 */

import React from "react";
import { render, screen, waitFor } from "@testing-library/react";
import "@testing-library/jest-dom";
import ReadingProgress from "@/components/blog/ReadingProgress";

describe("ReadingProgress Component", () => {
  // Store original window properties
  const originalScrollY = window.scrollY;
  const originalInnerHeight = window.innerHeight;

  beforeEach(() => {
    // Reset scroll position
    Object.defineProperty(window, "scrollY", {
      writable: true,
      configurable: true,
      value: 0,
    });

    // Mock window dimensions
    Object.defineProperty(window, "innerHeight", {
      writable: true,
      configurable: true,
      value: 1000,
    });

    // Mock document height
    Object.defineProperty(document.documentElement, "scrollHeight", {
      writable: true,
      configurable: true,
      value: 5000,
    });
  });

  afterEach(() => {
    // Restore original values
    Object.defineProperty(window, "scrollY", {
      writable: true,
      configurable: true,
      value: originalScrollY,
    });

    Object.defineProperty(window, "innerHeight", {
      writable: true,
      configurable: true,
      value: originalInnerHeight,
    });
  });

  describe("Initial Render", () => {
    it("should render the progress bar container", () => {
      const { container } = render(<ReadingProgress />);

      const progressContainer = container.firstChild;
      expect(progressContainer).toBeInTheDocument();
      expect(progressContainer).toHaveClass(
        "fixed",
        "top-0",
        "left-0",
        "right-0",
        "z-50",
        "h-1",
      );
    });

    it("should render with correct background colors", () => {
      const { container } = render(<ReadingProgress />);

      const progressContainer = container.firstChild;
      expect(progressContainer).toHaveClass("bg-gray-200", "dark:bg-slate-800");
    });

    it("should initialize with 0% progress", () => {
      const { container } = render(<ReadingProgress />);

      const progressBar = container.querySelector(".bg-gradient-to-r");
      expect(progressBar).toHaveStyle({ width: "0%" });
    });
  });

  describe("Progress Calculation", () => {
    it("should calculate 25% progress when scrolled 1/4 of the page", async () => {
      const { container } = render(<ReadingProgress />);

      // Scroll to 25% (1000 pixels out of 4000 scrollable)
      Object.defineProperty(window, "scrollY", {
        writable: true,
        configurable: true,
        value: 1000,
      });

      // Trigger scroll event
      window.dispatchEvent(new Event("scroll"));

      await waitFor(() => {
        const progressBar = container.querySelector(".bg-gradient-to-r");
        expect(progressBar).toHaveStyle({ width: "25%" });
      });
    });

    it("should calculate 50% progress when scrolled halfway", async () => {
      const { container } = render(<ReadingProgress />);

      // Scroll to 50% (2000 pixels out of 4000 scrollable)
      Object.defineProperty(window, "scrollY", {
        writable: true,
        configurable: true,
        value: 2000,
      });

      window.dispatchEvent(new Event("scroll"));

      await waitFor(() => {
        const progressBar = container.querySelector(".bg-gradient-to-r");
        expect(progressBar).toHaveStyle({ width: "50%" });
      });
    });

    it("should calculate 75% progress when scrolled 3/4 of the page", async () => {
      const { container } = render(<ReadingProgress />);

      // Scroll to 75% (3000 pixels out of 4000 scrollable)
      Object.defineProperty(window, "scrollY", {
        writable: true,
        configurable: true,
        value: 3000,
      });

      window.dispatchEvent(new Event("scroll"));

      await waitFor(() => {
        const progressBar = container.querySelector(".bg-gradient-to-r");
        expect(progressBar).toHaveStyle({ width: "75%" });
      });
    });

    it("should show 100% progress at bottom of page", async () => {
      const { container } = render(<ReadingProgress />);

      // Scroll to bottom (4000 pixels = scrollHeight - innerHeight)
      Object.defineProperty(window, "scrollY", {
        writable: true,
        configurable: true,
        value: 4000,
      });

      window.dispatchEvent(new Event("scroll"));

      await waitFor(() => {
        const progressBar = container.querySelector(".bg-gradient-to-r");
        expect(progressBar).toHaveStyle({ width: "100%" });
      });
    });

    it("should cap progress at 100% even if scrolled past bottom", async () => {
      const { container } = render(<ReadingProgress />);

      // Scroll beyond bottom
      Object.defineProperty(window, "scrollY", {
        writable: true,
        configurable: true,
        value: 5000,
      });

      window.dispatchEvent(new Event("scroll"));

      await waitFor(() => {
        const progressBar = container.querySelector(".bg-gradient-to-r");
        expect(progressBar).toHaveStyle({ width: "100%" });
      });
    });

    it("should keep progress at 0% for negative scroll values", async () => {
      const { container } = render(<ReadingProgress />);

      // Negative scroll (shouldn't happen in practice, but testing edge case)
      Object.defineProperty(window, "scrollY", {
        writable: true,
        configurable: true,
        value: -100,
      });

      window.dispatchEvent(new Event("scroll"));

      await waitFor(() => {
        const progressBar = container.querySelector(".bg-gradient-to-r");
        expect(progressBar).toHaveStyle({ width: "0%" });
      });
    });
  });

  describe("Scroll Event Listener", () => {
    it("should add scroll event listener on mount", () => {
      const addEventListenerSpy = jest.spyOn(window, "addEventListener");

      render(<ReadingProgress />);

      expect(addEventListenerSpy).toHaveBeenCalledWith(
        "scroll",
        expect.any(Function),
        { passive: true },
      );

      addEventListenerSpy.mockRestore();
    });

    it("should remove scroll event listener on unmount", () => {
      const removeEventListenerSpy = jest.spyOn(window, "removeEventListener");

      const { unmount } = render(<ReadingProgress />);
      unmount();

      expect(removeEventListenerSpy).toHaveBeenCalledWith(
        "scroll",
        expect.any(Function),
      );

      removeEventListenerSpy.mockRestore();
    });

    it("should use passive scroll listener for better performance", () => {
      const addEventListenerSpy = jest.spyOn(window, "addEventListener");

      render(<ReadingProgress />);

      const scrollCall = addEventListenerSpy.mock.calls.find(
        (call) => call[0] === "scroll",
      );

      expect(scrollCall?.[2]).toEqual({ passive: true });

      addEventListenerSpy.mockRestore();
    });

    it("should update progress on multiple scroll events", async () => {
      const { container } = render(<ReadingProgress />);

      // First scroll to 25%
      Object.defineProperty(window, "scrollY", {
        writable: true,
        configurable: true,
        value: 1000,
      });
      window.dispatchEvent(new Event("scroll"));

      await waitFor(() => {
        const progressBar = container.querySelector(".bg-gradient-to-r");
        expect(progressBar).toHaveStyle({ width: "25%" });
      });

      // Then scroll to 75%
      Object.defineProperty(window, "scrollY", {
        writable: true,
        configurable: true,
        value: 3000,
      });
      window.dispatchEvent(new Event("scroll"));

      await waitFor(() => {
        const progressBar = container.querySelector(".bg-gradient-to-r");
        expect(progressBar).toHaveStyle({ width: "75%" });
      });
    });
  });

  describe("Visual Styling", () => {
    it("should have gradient background on progress bar", () => {
      const { container } = render(<ReadingProgress />);

      const progressBar = container.querySelector(".bg-gradient-to-r");
      expect(progressBar).toHaveClass(
        "bg-gradient-to-r",
        "from-brand-green",
        "via-emerald-500",
        "to-teal-500",
      );
    });

    it("should have smooth transition animation", () => {
      const { container } = render(<ReadingProgress />);

      const progressBar = container.querySelector(".bg-gradient-to-r");
      expect(progressBar).toHaveClass(
        "transition-all",
        "duration-150",
        "ease-out",
      );
    });

    it("should have shadow effect", () => {
      const { container } = render(<ReadingProgress />);

      const progressBar = container.querySelector(".bg-gradient-to-r");
      expect(progressBar).toHaveClass("shadow-lg");
    });

    it("should render glow effect element", () => {
      const { container } = render(<ReadingProgress />);

      const glowElement = container.querySelector(".absolute.right-0");
      expect(glowElement).toBeInTheDocument();
      expect(glowElement).toHaveClass("bg-white/40", "blur-sm");
    });

    it("should be positioned at top of viewport", () => {
      const { container } = render(<ReadingProgress />);

      const progressContainer = container.firstChild;
      expect(progressContainer).toHaveClass("fixed", "top-0", "z-50");
    });
  });

  describe("Edge Cases", () => {
    it("should handle very short pages", async () => {
      Object.defineProperty(document.documentElement, "scrollHeight", {
        writable: true,
        configurable: true,
        value: 500, // Shorter than viewport
      });

      const { container } = render(<ReadingProgress />);

      // Trigger scroll
      window.dispatchEvent(new Event("scroll"));

      await waitFor(() => {
        const progressBar = container.querySelector(".bg-gradient-to-r");
        // For pages shorter than viewport, should handle gracefully
        expect(progressBar).toBeInTheDocument();
      });
    });

    it("should handle zero scrollHeight gracefully", async () => {
      Object.defineProperty(document.documentElement, "scrollHeight", {
        writable: true,
        configurable: true,
        value: 0,
      });

      const { container } = render(<ReadingProgress />);

      window.dispatchEvent(new Event("scroll"));

      await waitFor(() => {
        const progressBar = container.querySelector(".bg-gradient-to-r");
        expect(progressBar).toBeInTheDocument();
      });
    });

    it("should recalculate on window resize", async () => {
      const { container } = render(<ReadingProgress />);

      // Scroll to 50%
      Object.defineProperty(window, "scrollY", {
        writable: true,
        configurable: true,
        value: 2000,
      });
      window.dispatchEvent(new Event("scroll"));

      await waitFor(() => {
        const progressBar = container.querySelector(".bg-gradient-to-r");
        expect(progressBar).toHaveStyle({ width: "50%" });
      });

      // Change viewport height
      Object.defineProperty(window, "innerHeight", {
        writable: true,
        configurable: true,
        value: 1500,
      });

      // Trigger scroll event to recalculate
      window.dispatchEvent(new Event("scroll"));

      await waitFor(() => {
        const progressBar = container.querySelector(".bg-gradient-to-r");
        // Should recalculate based on new dimensions
        expect(progressBar).toBeInTheDocument();
      });
    });
  });

  describe("Accessibility", () => {
    it("should be visible but not interfere with page content", () => {
      const { container } = render(<ReadingProgress />);

      const progressContainer = container.firstChild;
      expect(progressContainer).toHaveClass("h-1"); // Thin, unobtrusive
      expect(progressContainer).toHaveClass("z-50"); // Above content
    });

    it("should not have interactive elements", () => {
      const { container } = render(<ReadingProgress />);

      const buttons = container.querySelectorAll("button");
      const links = container.querySelectorAll("a");

      expect(buttons.length).toBe(0);
      expect(links.length).toBe(0);
    });

    it("should use semantic div elements", () => {
      const { container } = render(<ReadingProgress />);

      expect(container.querySelector("div")).toBeInTheDocument();
    });
  });

  describe("Performance", () => {
    it("should render quickly", () => {
      const startTime = performance.now();
      render(<ReadingProgress />);
      const renderTime = performance.now() - startTime;

      expect(renderTime).toBeLessThan(100); // Should render in less than 100ms
    });

    it("should handle rapid scroll events", async () => {
      const { container } = render(<ReadingProgress />);

      // Simulate rapid scrolling
      for (let i = 0; i < 50; i++) {
        Object.defineProperty(window, "scrollY", {
          writable: true,
          configurable: true,
          value: i * 80,
        });
        window.dispatchEvent(new Event("scroll"));
      }

      // Should still work after rapid scrolling
      await waitFor(() => {
        const progressBar = container.querySelector(".bg-gradient-to-r");
        expect(progressBar).toBeInTheDocument();
      });
    });
  });
});
