/**
 * TextSizeControl Component Tests
 *
 * Tests for blog text size control component
 *
 * Test Coverage:
 * - Initial render and default state
 * - Size selection (small, medium, large)
 * - localStorage persistence
 * - Custom event dispatching
 * - Bilingual labels (Arabic/English)
 * - Callback functionality
 * - Active button styling
 * - Size display labels
 */

import React from "react";
import { render, screen, fireEvent, waitFor } from "@testing-library/react";
import "@testing-library/jest-dom";
import TextSizeControl from "@/components/blog/TextSizeControl";
import { TextSizeProvider } from "@/lib/contexts/TextSizeContext";

// Wrapper to provide context
function renderWithProvider(ui: React.ReactElement) {
  return render(<TextSizeProvider>{ui}</TextSizeProvider>);
}

describe("TextSizeControl Component", () => {
  let localStorageMock: { [key: string]: string };

  beforeEach(() => {
    // Clear localStorage
    localStorageMock = {};

    // Mock localStorage
    Storage.prototype.getItem = jest.fn(
      (key: string) => localStorageMock[key] || null,
    );
    Storage.prototype.setItem = jest.fn((key: string, value: string) => {
      localStorageMock[key] = value;
    });
    Storage.prototype.removeItem = jest.fn((key: string) => {
      delete localStorageMock[key];
    });

    // Mock window.dispatchEvent
    window.dispatchEvent = jest.fn();
  });

  afterEach(() => {
    jest.clearAllMocks();
  });

  describe("Initial Render", () => {
    it("should render the component", () => {
      renderWithProvider(<TextSizeControl lang="en" />);

      expect(screen.getByText("Text Size")).toBeInTheDocument();
    });

    it("should render all three size options", () => {
      renderWithProvider(<TextSizeControl lang="en" />);

      expect(screen.getByText("Small")).toBeInTheDocument();
      expect(screen.getByText("Medium")).toBeInTheDocument();
      expect(screen.getByText("Large")).toBeInTheDocument();
    });

    it("should default to medium size", () => {
      const { container } = renderWithProvider(<TextSizeControl lang="en" />);

      const mediumButton = screen.getByText("Medium").closest("button");
      expect(mediumButton).toHaveClass("from-brand-green", "to-emerald-600");
    });

    it("should have correct container styling", () => {
      const { container } = renderWithProvider(<TextSizeControl lang="en" />);

      const wrapper = container.firstChild;
      expect(wrapper).toHaveClass(
        "sticky",
        "top-24",
        "bg-white",
        "dark:bg-slate-800",
        "rounded-2xl",
        "shadow-lg",
      );
    });

    it("should display icon", () => {
      const { container } = renderWithProvider(<TextSizeControl lang="en" />);

      const icon = container.querySelector("svg");
      expect(icon).toBeInTheDocument();
      expect(icon).toHaveClass("text-brand-green");
    });
  });

  describe("Size Selection", () => {
    it("should change to small size when clicked", () => {
      renderWithProvider(<TextSizeControl lang="en" />);

      const smallButton = screen.getByText("Small").closest("button");
      fireEvent.click(smallButton!);

      expect(smallButton).toHaveClass("from-brand-green", "to-emerald-600");
    });

    it("should change to large size when clicked", () => {
      renderWithProvider(<TextSizeControl lang="en" />);

      const largeButton = screen.getByText("Large").closest("button");
      fireEvent.click(largeButton!);

      expect(largeButton).toHaveClass("from-brand-green", "to-emerald-600");
    });

    it("should update active state visually", () => {
      renderWithProvider(<TextSizeControl lang="en" />);

      const smallButton = screen.getByText("Small").closest("button");
      const mediumButton = screen.getByText("Medium").closest("button");

      // Initially medium is active
      expect(mediumButton).toHaveClass("from-brand-green");
      expect(smallButton).toHaveClass("bg-gray-100");

      // Click small
      fireEvent.click(smallButton!);

      expect(smallButton).toHaveClass("from-brand-green");
      expect(mediumButton).toHaveClass("bg-gray-100");
    });

    it("should show correct size labels for each option", () => {
      renderWithProvider(<TextSizeControl lang="en" />);

      expect(screen.getByText("14px")).toBeInTheDocument();
      expect(screen.getByText("18px")).toBeInTheDocument();
      expect(screen.getByText("22px")).toBeInTheDocument();
    });

    it("should handle multiple size changes", () => {
      renderWithProvider(<TextSizeControl lang="en" />);

      const smallButton = screen.getByText("Small").closest("button");
      const largeButton = screen.getByText("Large").closest("button");
      const mediumButton = screen.getByText("Medium").closest("button");

      fireEvent.click(smallButton!);
      expect(smallButton).toHaveClass("from-brand-green");

      fireEvent.click(largeButton!);
      expect(largeButton).toHaveClass("from-brand-green");

      fireEvent.click(mediumButton!);
      expect(mediumButton).toHaveClass("from-brand-green");
    });
  });

  describe("localStorage Persistence", () => {
    it("should save size to localStorage when changed", () => {
      renderWithProvider(<TextSizeControl lang="en" />);

      const smallButton = screen.getByText("Small").closest("button");
      fireEvent.click(smallButton!);

      expect(localStorage.setItem).toHaveBeenCalledWith(
        "blog-text-size",
        "small",
      );
    });

    it("should save medium size to localStorage", () => {
      renderWithProvider(<TextSizeControl lang="en" />);

      const mediumButton = screen.getByText("Medium").closest("button");
      fireEvent.click(mediumButton!);

      expect(localStorage.setItem).toHaveBeenCalledWith(
        "blog-text-size",
        "medium",
      );
    });

    it("should save large size to localStorage", () => {
      renderWithProvider(<TextSizeControl lang="en" />);

      const largeButton = screen.getByText("Large").closest("button");
      fireEvent.click(largeButton!);

      expect(localStorage.setItem).toHaveBeenCalledWith(
        "blog-text-size",
        "large",
      );
    });

    it("should load saved size from localStorage on mount", async () => {
      localStorageMock["blog-text-size"] = "large";

      renderWithProvider(<TextSizeControl lang="en" />);

      await waitFor(() => {
        const largeButton = screen.getByText("Large").closest("button");
        expect(largeButton).toHaveClass("from-brand-green");
      });
    });

    it("should load small size from localStorage", async () => {
      localStorageMock["blog-text-size"] = "small";

      renderWithProvider(<TextSizeControl lang="en" />);

      await waitFor(() => {
        const smallButton = screen.getByText("Small").closest("button");
        expect(smallButton).toHaveClass("from-brand-green");
      });
    });

    it("should ignore invalid values from localStorage", async () => {
      localStorageMock["blog-text-size"] = "invalid-size";

      renderWithProvider(<TextSizeControl lang="en" />);

      await waitFor(() => {
        // Should default to medium
        const mediumButton = screen.getByText("Medium").closest("button");
        expect(mediumButton).toHaveClass("from-brand-green");
      });
    });

    it("should handle missing localStorage value", async () => {
      renderWithProvider(<TextSizeControl lang="en" />);

      await waitFor(() => {
        // Should default to medium
        const mediumButton = screen.getByText("Medium").closest("button");
        expect(mediumButton).toHaveClass("from-brand-green");
      });
    });
  });

  // Events are now handled via React context, not custom DOM events
  describe.skip("Custom Event Dispatching", () => {
    it("should dispatch textSizeChange event when size changes", () => {
      renderWithProvider(<TextSizeControl lang="en" />);

      const smallButton = screen.getByText("Small").closest("button");
      fireEvent.click(smallButton!);

      expect(window.dispatchEvent).toHaveBeenCalledWith(
        expect.objectContaining({
          type: "textSizeChange",
          detail: "small",
        }),
      );
    });

    it("should dispatch event with correct size for medium", () => {
      renderWithProvider(<TextSizeControl lang="en" />);

      const mediumButton = screen.getByText("Medium").closest("button");
      fireEvent.click(mediumButton!);

      expect(window.dispatchEvent).toHaveBeenCalledWith(
        expect.objectContaining({
          type: "textSizeChange",
          detail: "medium",
        }),
      );
    });

    it("should dispatch event with correct size for large", () => {
      renderWithProvider(<TextSizeControl lang="en" />);

      const largeButton = screen.getByText("Large").closest("button");
      fireEvent.click(largeButton!);

      expect(window.dispatchEvent).toHaveBeenCalledWith(
        expect.objectContaining({
          type: "textSizeChange",
          detail: "large",
        }),
      );
    });
  });

  // Callback prop removed; state is managed via context
  describe.skip("Callback Functionality", () => {
    it("should call onSizeChange callback when size changes", () => {
      const mockCallback = jest.fn();
      renderWithProvider(
        <TextSizeControl lang="en" onSizeChange={mockCallback} />,
      );

      const smallButton = screen.getByText("Small").closest("button");
      fireEvent.click(smallButton!);

      expect(mockCallback).toHaveBeenCalledWith("small");
    });

    it("should call callback with medium size", () => {
      const mockCallback = jest.fn();
      renderWithProvider(
        <TextSizeControl lang="en" onSizeChange={mockCallback} />,
      );

      const mediumButton = screen.getByText("Medium").closest("button");
      fireEvent.click(mediumButton!);

      expect(mockCallback).toHaveBeenCalledWith("medium");
    });

    it("should call callback with large size", () => {
      const mockCallback = jest.fn();
      renderWithProvider(
        <TextSizeControl lang="en" onSizeChange={mockCallback} />,
      );

      const largeButton = screen.getByText("Large").closest("button");
      fireEvent.click(largeButton!);

      expect(mockCallback).toHaveBeenCalledWith("large");
    });

    it("should call callback on initial load from localStorage", async () => {
      localStorageMock["blog-text-size"] = "large";
      const mockCallback = jest.fn();

      renderWithProvider(
        <TextSizeControl lang="en" onSizeChange={mockCallback} />,
      );

      await waitFor(() => {
        expect(mockCallback).toHaveBeenCalledWith("large");
      });
    });

    it("should not throw if callback is not provided", () => {
      renderWithProvider(<TextSizeControl lang="en" />);

      const smallButton = screen.getByText("Small").closest("button");

      expect(() => fireEvent.click(smallButton!)).not.toThrow();
    });

    it("should call callback multiple times for multiple changes", () => {
      const mockCallback = jest.fn();
      renderWithProvider(
        <TextSizeControl lang="en" onSizeChange={mockCallback} />,
      );

      fireEvent.click(screen.getByText("Small").closest("button")!);
      fireEvent.click(screen.getByText("Large").closest("button")!);
      fireEvent.click(screen.getByText("Medium").closest("button")!);

      expect(mockCallback).toHaveBeenCalledTimes(3);
      expect(mockCallback).toHaveBeenNthCalledWith(1, "small");
      expect(mockCallback).toHaveBeenNthCalledWith(2, "large");
      expect(mockCallback).toHaveBeenNthCalledWith(3, "medium");
    });
  });

  describe("Bilingual Support - English", () => {
    it("should render English labels", () => {
      renderWithProvider(<TextSizeControl lang="en" />);

      expect(screen.getByText("Text Size")).toBeInTheDocument();
      expect(screen.getByText("Small")).toBeInTheDocument();
      expect(screen.getByText("Medium")).toBeInTheDocument();
      expect(screen.getByText("Large")).toBeInTheDocument();
    });

    it("should show English size labels", () => {
      renderWithProvider(<TextSizeControl lang="en" />);

      expect(screen.getByText("14px")).toBeInTheDocument();
      expect(screen.getByText("18px")).toBeInTheDocument();
      expect(screen.getByText("22px")).toBeInTheDocument();
    });

    it("should show English preference message", () => {
      renderWithProvider(<TextSizeControl lang="en" />);

      expect(
        screen.getByText("Your preference is saved automatically"),
      ).toBeInTheDocument();
    });
  });

  describe("Bilingual Support - Arabic", () => {
    it("should render Arabic labels", () => {
      renderWithProvider(<TextSizeControl lang="ar" />);

      expect(screen.getByText("حجم النص")).toBeInTheDocument();
      expect(screen.getByText("صغير")).toBeInTheDocument();
      expect(screen.getByText("متوسط")).toBeInTheDocument();
      expect(screen.getByText("كبير")).toBeInTheDocument();
    });

    it("should show Arabic size labels", () => {
      renderWithProvider(<TextSizeControl lang="ar" />);

      expect(screen.getByText("14 بكسل")).toBeInTheDocument();
      expect(screen.getByText("18 بكسل")).toBeInTheDocument();
      expect(screen.getByText("22 بكسل")).toBeInTheDocument();
    });

    it("should show Arabic preference message", () => {
      renderWithProvider(<TextSizeControl lang="ar" />);

      expect(screen.getByText("تفضيلك محفوظ تلقائياً")).toBeInTheDocument();
    });

    it("should function correctly in Arabic mode", () => {
      renderWithProvider(<TextSizeControl lang="ar" />);

      const smallButton = screen.getByText("صغير").closest("button");
      fireEvent.click(smallButton!);

      expect(localStorage.setItem).toHaveBeenCalledWith(
        "blog-text-size",
        "small",
      );
      expect(smallButton).toHaveClass("from-brand-green");
    });
  });

  describe("Button Styling", () => {
    it("should style active button with gradient", () => {
      renderWithProvider(<TextSizeControl lang="en" />);

      const mediumButton = screen.getByText("Medium").closest("button");
      expect(mediumButton).toHaveClass(
        "bg-gradient-to-r",
        "from-brand-green",
        "to-emerald-600",
        "text-white",
        "shadow-md",
      );
    });

    it("should style inactive buttons with gray background", () => {
      renderWithProvider(<TextSizeControl lang="en" />);

      const smallButton = screen.getByText("Small").closest("button");
      expect(smallButton).toHaveClass(
        "bg-gray-100",
        "dark:bg-slate-700",
        "text-gray-700",
        "dark:text-gray-300",
      );
    });

    it("should apply hover styles to inactive buttons", () => {
      renderWithProvider(<TextSizeControl lang="en" />);

      const smallButton = screen.getByText("Small").closest("button");
      expect(smallButton).toHaveClass(
        "hover:bg-gray-200",
        "dark:hover:bg-slate-600",
      );
    });

    it("should have transition animations", () => {
      renderWithProvider(<TextSizeControl lang="en" />);

      const buttons = screen.getAllByRole("button").slice(0, 3); // First 3 are size buttons
      buttons.forEach((button) => {
        expect(button).toHaveClass("transition-all", "duration-200");
      });
    });
  });

  describe("Layout and Structure", () => {
    it("should use flexbox layout for button content", () => {
      const { container } = renderWithProvider(<TextSizeControl lang="en" />);

      const buttonContent = container.querySelector(
        ".flex.items-center.justify-between",
      );
      expect(buttonContent).toBeInTheDocument();
    });

    it("should have spacing between buttons", () => {
      const { container } = renderWithProvider(<TextSizeControl lang="en" />);

      const buttonContainer = container.querySelector(".space-y-2");
      expect(buttonContainer).toBeInTheDocument();
    });

    it("should have border separator before footer message", () => {
      const { container } = renderWithProvider(<TextSizeControl lang="en" />);

      const footer = container.querySelector(".border-t");
      expect(footer).toBeInTheDocument();
      expect(footer).toHaveClass("border-gray-200", "dark:border-slate-700");
    });

    it("should center-align preference message", () => {
      const { container } = renderWithProvider(<TextSizeControl lang="en" />);

      const message = screen.getByText(
        "Your preference is saved automatically",
      );
      expect(message).toHaveClass("text-center");
    });
  });

  describe("Accessibility", () => {
    it("should render all options as buttons", () => {
      renderWithProvider(<TextSizeControl lang="en" />);

      const buttons = screen.getAllByRole("button");
      expect(buttons.length).toBeGreaterThanOrEqual(3);
    });

    it("should have proper heading hierarchy", () => {
      const { container } = renderWithProvider(<TextSizeControl lang="en" />);

      const heading = screen.getByText("Text Size");
      expect(heading.tagName).toBe("H3");
    });

    it("should have accessible button text", () => {
      renderWithProvider(<TextSizeControl lang="en" />);

      const smallButton = screen.getByText("Small").closest("button");
      expect(smallButton?.textContent).toContain("Small");
      expect(smallButton?.textContent).toContain("14px");
    });

    it("should maintain focus on button after click", () => {
      renderWithProvider(<TextSizeControl lang="en" />);

      const smallButton = screen
        .getByText("Small")
        .closest("button") as HTMLButtonElement;
      smallButton.focus();
      fireEvent.click(smallButton);

      // Button should still be focusable
      expect(document.activeElement).toBe(smallButton);
    });
  });

  describe("Edge Cases", () => {
    it("should handle rapid clicks", () => {
      renderWithProvider(<TextSizeControl lang="en" />);

      const smallButton = screen.getByText("Small").closest("button")!;

      // Rapid clicks
      for (let i = 0; i < 10; i++) {
        fireEvent.click(smallButton);
      }

      // Should not crash
      expect(screen.getByText("Small")).toBeInTheDocument();
    });

    it("should handle clicking same size multiple times", () => {
      renderWithProvider(<TextSizeControl lang="en" />);

      const mediumButton = screen.getByText("Medium").closest("button")!;

      fireEvent.click(mediumButton);
      fireEvent.click(mediumButton);
      fireEvent.click(mediumButton);

      expect(mediumButton).toHaveClass("from-brand-green");
    });

    it("should handle localStorage being unavailable", () => {
      // Mock localStorage to throw error
      Storage.prototype.setItem = jest.fn(() => {
        throw new Error("localStorage is full");
      });

      // Context handles localStorage errors internally
      renderWithProvider(<TextSizeControl lang="en" />);

      const smallButton = screen.getByText("Small").closest("button")!;

      // Should not throw - context handles errors gracefully
      fireEvent.click(smallButton);
      expect(smallButton).toBeInTheDocument();
    });
  });

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

      expect(renderTime).toBeLessThan(100);
    });

    it("should update state efficiently", () => {
      renderWithProvider(<TextSizeControl lang="en" />);

      const startTime = performance.now();
      fireEvent.click(screen.getByText("Small").closest("button")!);
      const updateTime = performance.now() - startTime;

      expect(updateTime).toBeLessThan(50);
    });
  });
});
