import { renderHook } from "@testing-library/react-hooks";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";

import { useUserAgentData } from "./useUserAgentData";

describe("useUserAgentData hook", () => {
  const originalNavigator = global.navigator;

  beforeEach(() => {
    vi.useFakeTimers();
  });

  afterEach(() => {
    vi.useRealTimers();
    Object.defineProperty(global, "navigator", {
      value: originalNavigator,
      writable: true,
    });
  });

  function mockUserAgent(userAgent: string) {
    Object.defineProperty(global, "navigator", {
      value: { userAgent },
      writable: true,
    });
  }

  describe("OS detection", () => {
    it("should detect iOS on iPhone", () => {
      mockUserAgent(
        "Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Mobile/15E148 Safari/604.1"
      );
      const { result } = renderHook(() => useUserAgentData());
      expect(result.current.os).toBe("ios");
      expect(result.current.isMobile).toBe(true);
    });

    it("should detect iOS on iPad", () => {
      mockUserAgent(
        "Mozilla/5.0 (iPad; CPU OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Mobile/15E148 Safari/604.1"
      );
      const { result } = renderHook(() => useUserAgentData());
      expect(result.current.os).toBe("ios");
      expect(result.current.isMobile).toBe(true);
    });

    it("should detect Android", () => {
      mockUserAgent(
        "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Mobile Safari/537.36"
      );
      const { result } = renderHook(() => useUserAgentData());
      expect(result.current.os).toBe("android");
      expect(result.current.isMobile).toBe(true);
    });

    it("should detect macOS", () => {
      mockUserAgent(
        "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36"
      );
      const { result } = renderHook(() => useUserAgentData());
      expect(result.current.os).toBe("macos");
      expect(result.current.isMobile).toBe(false);
    });

    it("should detect Windows", () => {
      mockUserAgent(
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36"
      );
      const { result } = renderHook(() => useUserAgentData());
      expect(result.current.os).toBe("windows");
      expect(result.current.isMobile).toBe(false);
    });

    it("should detect Linux", () => {
      mockUserAgent(
        "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36"
      );
      const { result } = renderHook(() => useUserAgentData());
      expect(result.current.os).toBe("linux");
      expect(result.current.isMobile).toBe(false);
    });

    it("should return unknown for unrecognized OS", () => {
      mockUserAgent("Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)");
      const { result } = renderHook(() => useUserAgentData());
      expect(result.current.os).toBe("unknown");
      expect(result.current.isMobile).toBe(false);
    });
  });

  describe("Browser detection", () => {
    it("should detect Chrome on desktop", () => {
      mockUserAgent(
        "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36"
      );
      const { result } = renderHook(() => useUserAgentData());
      expect(result.current.browser).toBe("chrome");
    });

    it("should detect Chrome on iOS (CriOS)", () => {
      mockUserAgent(
        "Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/116.0.5845.103 Mobile/15E148 Safari/604.1"
      );
      const { result } = renderHook(() => useUserAgentData());
      expect(result.current.browser).toBe("chrome");
    });

    it("should detect Safari on macOS", () => {
      mockUserAgent(
        "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Safari/605.1.15"
      );
      const { result } = renderHook(() => useUserAgentData());
      expect(result.current.browser).toBe("safari");
    });

    it("should detect Safari on iOS", () => {
      mockUserAgent(
        "Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Mobile/15E148 Safari/604.1"
      );
      const { result } = renderHook(() => useUserAgentData());
      expect(result.current.browser).toBe("safari");
    });

    it("should detect Firefox on desktop", () => {
      mockUserAgent("Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/116.0");
      const { result } = renderHook(() => useUserAgentData());
      expect(result.current.browser).toBe("firefox");
    });

    it("should detect Firefox on iOS (FxiOS)", () => {
      mockUserAgent(
        "Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) FxiOS/116.0 Mobile/15E148 Safari/605.1.15"
      );
      const { result } = renderHook(() => useUserAgentData());
      expect(result.current.browser).toBe("firefox");
    });

    it("should detect Edge", () => {
      mockUserAgent(
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36 Edg/116.0.1938.69"
      );
      const { result } = renderHook(() => useUserAgentData());
      expect(result.current.browser).toBe("edge");
    });

    it("should not detect Chrome when Edge is present", () => {
      mockUserAgent(
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36 Edg/116.0.1938.69"
      );
      const { result } = renderHook(() => useUserAgentData());
      expect(result.current.browser).toBe("edge");
      expect(result.current.browser).not.toBe("chrome");
    });

    it("should return unknown for unrecognized browser", () => {
      mockUserAgent("Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)");
      const { result } = renderHook(() => useUserAgentData());
      expect(result.current.browser).toBe("unknown");
    });
  });

  describe("SSR handling", () => {
    it("should return defaults when navigator is undefined", () => {
      Object.defineProperty(global, "navigator", {
        value: undefined,
        writable: true,
      });
      const { result } = renderHook(() => useUserAgentData());
      expect(result.current.os).toBe("unknown");
      expect(result.current.browser).toBe("unknown");
      expect(result.current.isMobile).toBe(false);
    });
  });
});
