/**
 * Integration Tests for Provider Tree Order (Issue #54)
 *
 * Verifies that the provider tree is correctly nested per PROVIDER_ORDER.md.
 * These tests complement compile-time checks by validating runtime structure.
 */

import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
import { render, screen, waitFor } from "@testing-library/react";
import { MemoryRouter } from "react-router-dom";
import { createProviderComposition } from "../providerComposition";
import { ThemeProvider } from "../ThemeProvider";
import { AuthProvider } from "../AuthProvider";
import { TimezoneProvider } from "../TimezoneProvider";
import { NavigationCancellationProvider } from "../NavigationCancellationProvider";
import * as clientModule from "../../api/client";
import * as authModule from "../../api/auth";

// ---------------------------------------------------------------------------
// Helper: Simple component to verify each provider's context is accessible
// ---------------------------------------------------------------------------

function AuthConsumer(): React.JSX.Element {
  return <div data-testid="auth-available">Auth available</div>;
}

// ---------------------------------------------------------------------------
// Test Suite: Provider Tree Order Integration
// ---------------------------------------------------------------------------

describe("Provider Tree Order Integration", () => {
  beforeEach(() => {
    sessionStorage.clear();
    localStorage.clear();
    vi.clearAllMocks();
    vi.restoreAllMocks();

    Object.defineProperty(window, "matchMedia", {
      configurable: true,
      writable: true,
      value: vi.fn().mockReturnValue({
        matches: false,
        addEventListener: vi.fn(),
        removeEventListener: vi.fn(),
      }),
    });

    vi.spyOn(clientModule, "setUnauthorizedHandler").mockImplementation(
      (_handler: (() => void) | null) => {},
    );

    // Mock session validation to prevent auth errors
    vi.spyOn(authModule, "validateSession").mockResolvedValue({
      valid: true,
    });
  });

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

  // -----------------------------------------------------------------------
  // Test 1: createProviderComposition renders providers without crashing
  // -----------------------------------------------------------------------

  it("builder creates composition that renders without errors", async () => {
    const composition = createProviderComposition()
      .withTheme({ children: undefined })
      .withFluent({} as any)
      .withNotification()
      .withErrorBoundary()
      .withBrowserRouter()
      .withNavigationCancellation()
      .withAuth()
      .build(<AuthConsumer />);

    render(composition);

    await waitFor(() => {
      expect(screen.getByTestId("auth-available")).toBeInTheDocument();
    });
  });

  // -----------------------------------------------------------------------
  // Test 2: App provider structure matches PROVIDER_ORDER.md
  // -----------------------------------------------------------------------

  it("App providers nested as documented in PROVIDER_ORDER.md", async () => {
    function Inner(): React.JSX.Element {
      return <div data-testid="inner">Inner</div>;
    }

    // Recreate the core provider nesting from App.tsx
    const composition = (
      <ThemeProvider>
        <MemoryRouter initialEntries={["/"]}>
          <NavigationCancellationProvider>
            <AuthProvider>
              <TimezoneProvider>
                <Inner />
              </TimezoneProvider>
            </AuthProvider>
          </NavigationCancellationProvider>
        </MemoryRouter>
      </ThemeProvider>
    );

    render(composition);

    await waitFor(() => {
      expect(screen.getByTestId("inner")).toBeInTheDocument();
    });
  });

  // -----------------------------------------------------------------------
  // Test 3: Incorrect provider nesting (BrowserRouter missing) is detected
  // -----------------------------------------------------------------------

  it("throws when AuthProvider is outside BrowserRouter", async () => {
    // AuthProvider uses useNavigate() which requires BrowserRouter context.
    // If placed outside BrowserRouter, it should throw.

    function BadlyNested(): React.JSX.Element {
      return (
        <ThemeProvider>
          <AuthProvider>
            <div>Should fail</div>
          </AuthProvider>
        </ThemeProvider>
      );
    }

    expect(() => render(<BadlyNested />)).toThrow();
  });

  // -----------------------------------------------------------------------
  // Test 4: Provider order matters - FluentProvider needs theme from ThemeProvider
  // -----------------------------------------------------------------------

  it("verify that ThemeProvider and FluentProvider order matters", async () => {
    // FluentProvider needs theme from ThemeProvider via useThemeMode().
    // This test verifies they work together when correctly nested.

    function FluentContent(): React.JSX.Element {
      return <div data-testid="fluent-content">Fluent content</div>;
    }

    const composition = createProviderComposition()
      .withTheme({ children: undefined })
      .withFluent({} as any)
      .withNotification()
      .withErrorBoundary()
      .withBrowserRouter()
      .withNavigationCancellation()
      .withAuth()
      .build(<FluentContent />);

    render(composition);

    await waitFor(() => {
      expect(screen.getByTestId("fluent-content")).toBeInTheDocument();
    });
  });

  // -----------------------------------------------------------------------
  // Test 5: buildWithTimezone adds TimezoneProvider after AuthProvider
  // -----------------------------------------------------------------------

  it("buildWithTimezone() includes TimezoneProvider for protected routes", async () => {
    function TimezoneContent(): React.JSX.Element {
      return <div data-testid="timezone-content">Timezone content</div>;
    }

    const composition = createProviderComposition()
      .withTheme({ children: undefined })
      .withFluent({} as any)
      .withNotification()
      .withErrorBoundary()
      .withBrowserRouter()
      .withNavigationCancellation()
      .withAuth()
      .withTimezone({ children: <TimezoneContent /> })
      .buildWithTimezone();

    // Just verify it renders without throwing - ordering is enforced by builder
    render(composition);

    await waitFor(() => {
      expect(screen.getByTestId("timezone-content")).toBeInTheDocument();
    });
  });

  // -----------------------------------------------------------------------
  // Test 6: All providers render without errors (nesting depth check)
  // -----------------------------------------------------------------------

  it("composition with all providers renders correctly", async () => {
    function AllProvidersContent(): React.JSX.Element {
      return <div data-testid="all-providers">All providers rendered</div>;
    }

    const composition = createProviderComposition()
      .withTheme({ children: undefined })
      .withFluent({} as any)
      .withNotification()
      .withErrorBoundary()
      .withBrowserRouter()
      .withNavigationCancellation()
      .withAuth()
      .withTimezone({ children: <AllProvidersContent /> })
      .buildWithTimezone();

    render(composition);

    await waitFor(() => {
      expect(screen.getByTestId("all-providers")).toBeInTheDocument();
    });
  });
});
