/**
 * Provider Composition Utility — Compile-Time Provider Ordering Validation
 *
 * This module enforces the provider nesting order at compile-time using TypeScript's
 * discriminated unions. The provider hierarchy is strictly enforced and cannot be
 * violated without TypeScript errors.
 *
 * Provider Order (enforced at compile-time):
 *  1. ThemeProvider        (OUTERMOST — must be first)
 *  2. FluentProvider       (wraps all Fluent UI consumers)
 *  3. NotificationProvider (must wrap error boundaries)
 *  4. ErrorBoundary        (top-level error boundary)
 *  5. BrowserRouter        (enables routing)
 *  6. NavigationCancellationProvider (manages route cancellation)
 *  7. AuthProvider         (session validation)
 *  8. TimezoneProvider     (INNERMOST — wraps protected routes only)
 *
 * Usage:
 *  ```tsx
 *  const providerStack = createProviderComposition()
 *    .withTheme({ children })
 *    .withFluent(theme)
 *    .withNotification()
 *    .build();
 *  ```
 *
 * TypeScript will prevent any attempt to add providers out of order:
 *  ```tsx
 *  const invalid = createProviderComposition()
 *    .withFluent(theme)  // ❌ TypeScript Error: cannot call withFluent before withTheme
 *    .withTheme({ children });
 *  ```
 */

import type { ReactElement, ReactNode } from "react";
import { FluentProvider } from "@fluentui/react-components";
import type { Theme } from "@fluentui/react-components";
import { BrowserRouter } from "react-router-dom";
import { ThemeProvider } from "./ThemeProvider";
import { AuthProvider } from "./AuthProvider";
import { TimezoneProvider } from "./TimezoneProvider";
import { NavigationCancellationProvider } from "./NavigationCancellationProvider";
import { NotificationProvider } from "../services/notificationService";
import { ErrorBoundary } from "../components/ErrorBoundary";
import { NotificationContainer } from "../components/NotificationContainer";

// ============================================================================
// Type Definitions — Discriminated Union Pattern
// ============================================================================

/**
 * State 0: Initial state — only ThemeProvider can be added
 */
interface ProviderState0 {
  readonly __state: 0;
}

/**
 * State 1: ThemeProvider added — FluentProvider can be added next
 */
interface ProviderState1 {
  readonly __state: 1;
  readonly themeChildren: ReactNode;
}

/**
 * State 2: FluentProvider added — NotificationProvider can be added next
 */
interface ProviderState2 {
  readonly __state: 2;
  readonly themeChildren: ReactNode;
  readonly theme: Theme;
}

/**
 * State 3: NotificationProvider added — ErrorBoundary can be added next
 */
interface ProviderState3 {
  readonly __state: 3;
  readonly themeChildren: ReactNode;
  readonly theme: Theme;
}

/**
 * State 4: ErrorBoundary added — BrowserRouter can be added next
 */
interface ProviderState4 {
  readonly __state: 4;
  readonly themeChildren: ReactNode;
  readonly theme: Theme;
}

/**
 * State 5: BrowserRouter added — NavigationCancellationProvider can be added next
 */
interface ProviderState5 {
  readonly __state: 5;
  readonly themeChildren: ReactNode;
  readonly theme: Theme;
}

/**
 * State 6: NavigationCancellationProvider added — AuthProvider can be added next
 */
interface ProviderState6 {
  readonly __state: 6;
  readonly themeChildren: ReactNode;
  readonly theme: Theme;
}

/**
 * State 7: AuthProvider added — TimezoneProvider can be added next (or build can be called)
 */
interface ProviderState7 {
  readonly __state: 7;
  readonly themeChildren: ReactNode;
  readonly theme: Theme;
}

/**
 * State 8: TimezoneProvider added — ready to build final component
 */
interface ProviderState8 {
  readonly __state: 8;
  readonly themeChildren: ReactNode;
  readonly theme: Theme;
  readonly timezoneChildren: ReactNode;
}

type ProviderCompositionState = ProviderState0 | ProviderState1 | ProviderState2 | ProviderState3 | ProviderState4 | ProviderState5 | ProviderState6 | ProviderState7 | ProviderState8;

// ============================================================================
// Builder — Type-Safe Provider Composition
// ============================================================================

/**
 * Type-safe builder for composing providers in the correct order.
 *
 * Each method returns a builder in the next state, ensuring providers
 * can only be added in the documented order.
 */
class ProviderCompositionBuilder<TState extends ProviderCompositionState> {
  /**
   * Create a new builder in its initial state.
   */
  static create(): ProviderCompositionBuilder<ProviderState0> {
    return new ProviderCompositionBuilder({ __state: 0 });
  }

  private constructor(private state: TState) {}

  /**
   * Add ThemeProvider (Step 1: OUTERMOST).
   *
   * This must be called first. ThemeProvider supplies theme context
   * to all descendants via useThemeMode().
   */
  withTheme(
    this: ProviderCompositionBuilder<ProviderState0>,
    props: { children: ReactNode }
  ): ProviderCompositionBuilder<ProviderState1> {
    return new ProviderCompositionBuilder({
      __state: 1,
      themeChildren: props.children,
    } as unknown as ProviderState1);
  }

  /**
   * Add FluentProvider (Step 2).
   *
   * Must come after ThemeProvider. Supplies Fluent UI theme and design tokens
   * to all Fluent UI components.
   */
  withFluent(
    this: ProviderCompositionBuilder<ProviderState1>,
    theme: Theme
  ): ProviderCompositionBuilder<ProviderState2> {
    return new ProviderCompositionBuilder({
      __state: 2,
      themeChildren: this.state.themeChildren,
      theme,
    } as unknown as ProviderState2);
  }

  /**
   * Add NotificationProvider (Step 3).
   *
   * Must come after FluentProvider. Makes useNotification() available
   * to error boundaries and other components.
   */
  withNotification(
    this: ProviderCompositionBuilder<ProviderState2>
  ): ProviderCompositionBuilder<ProviderState3> {
    return new ProviderCompositionBuilder({
      __state: 3,
      themeChildren: this.state.themeChildren,
      theme: this.state.theme,
    } as unknown as ProviderState3);
  }

  /**
   * Add ErrorBoundary (Step 4).
   *
   * Must come after NotificationProvider. Catches catastrophic errors
   * that would crash the entire app.
   */
  withErrorBoundary(
    this: ProviderCompositionBuilder<ProviderState3>
  ): ProviderCompositionBuilder<ProviderState4> {
    return new ProviderCompositionBuilder({
      __state: 4,
      themeChildren: this.state.themeChildren,
      theme: this.state.theme,
    } as unknown as ProviderState4);
  }

  /**
   * Add BrowserRouter (Step 5).
   *
   * Must come after ErrorBoundary. Enables client-side routing and
   * supports useNavigate() in downstream providers.
   */
  withBrowserRouter(
    this: ProviderCompositionBuilder<ProviderState4>
  ): ProviderCompositionBuilder<ProviderState5> {
    return new ProviderCompositionBuilder({
      __state: 5,
      themeChildren: this.state.themeChildren,
      theme: this.state.theme,
    } as unknown as ProviderState5);
  }

  /**
   * Add NavigationCancellationProvider (Step 6).
   *
   * Must come after BrowserRouter. Manages route-aware request cancellation
   * using useLocation() to detect route changes.
   */
  withNavigationCancellation(
    this: ProviderCompositionBuilder<ProviderState5>
  ): ProviderCompositionBuilder<ProviderState6> {
    return new ProviderCompositionBuilder({
      __state: 6,
      themeChildren: this.state.themeChildren,
      theme: this.state.theme,
    } as unknown as ProviderState6);
  }

  /**
   * Add AuthProvider (Step 7).
   *
   * Must come after NavigationCancellationProvider. Validates session
   * on mount and provides useAuth() context to all descendants.
   */
  withAuth(
    this: ProviderCompositionBuilder<ProviderState6>
  ): ProviderCompositionBuilder<ProviderState7> {
    return new ProviderCompositionBuilder({
      __state: 7,
      themeChildren: this.state.themeChildren,
      theme: this.state.theme,
    } as unknown as ProviderState7);
  }

  /**
   * Add TimezoneProvider (Step 8: INNERMOST).
   *
   * Optional. Must come after AuthProvider if used. Wraps protected routes
   * and fetches timezone from the backend.
   */
  withTimezone(
    this: ProviderCompositionBuilder<ProviderState7>,
    props: { children: ReactNode }
  ): ProviderCompositionBuilder<ProviderState8> {
    return new ProviderCompositionBuilder({
      __state: 8,
      themeChildren: this.state.themeChildren,
      theme: this.state.theme,
      timezoneChildren: props.children,
    } as unknown as ProviderState8);
  }

  /**
   * Build the final composed provider tree without TimezoneProvider.
   * Use this for routes that don't need timezone data (e.g., setup, login).
   */
  build(
    this: ProviderCompositionBuilder<ProviderState7>,
    innerContent: ReactNode
  ): ReactElement {
    const s = this.state;
    return (
      <ThemeProvider>
        <FluentProvider theme={s.theme}>
          <NotificationProvider>
            <ErrorBoundary
              title="Application Error"
              message="The application encountered a critical error. Reloading may help."
              isFullPage={true}
            >
              <NotificationContainer />
              <BrowserRouter future={{ v7_startTransition: true, v7_relativeSplatPath: true }}>
                <NavigationCancellationProvider>
                  <AuthProvider>
                    {innerContent}
                  </AuthProvider>
                </NavigationCancellationProvider>
              </BrowserRouter>
            </ErrorBoundary>
          </NotificationProvider>
        </FluentProvider>
      </ThemeProvider>
    );
  }

  /**
   * Build the final composed provider tree with TimezoneProvider.
   * Use this for protected routes that need timezone data.
   */
  buildWithTimezone(
    this: ProviderCompositionBuilder<ProviderState8>
  ): ReactElement {
    const s = this.state;
    return (
      <ThemeProvider>
        <FluentProvider theme={s.theme}>
          <NotificationProvider>
            <ErrorBoundary
              title="Application Error"
              message="The application encountered a critical error. Reloading may help."
              isFullPage={true}
            >
              <NotificationContainer />
              <BrowserRouter future={{ v7_startTransition: true, v7_relativeSplatPath: true }}>
                <NavigationCancellationProvider>
                  <AuthProvider>
                    <TimezoneProvider>
                      {s.timezoneChildren}
                    </TimezoneProvider>
                  </AuthProvider>
                </NavigationCancellationProvider>
              </BrowserRouter>
            </ErrorBoundary>
          </NotificationProvider>
        </FluentProvider>
      </ThemeProvider>
    );
  }
}

export { ProviderCompositionBuilder };

/**
 * Factory function to create a new provider composition builder.
 *
 * @returns A new builder in state 0 (ready for ThemeProvider)
 *
 * @example
 * ```tsx
 * const providerStack = createProviderComposition()
 *   .withTheme({ children })
 *   .withFluent(theme)
 *   .withNotification()
 *   .withErrorBoundary()
 *   .withBrowserRouter()
 *   .withNavigationCancellation()
 *   .withAuth()
 *   .build(routes);
 * ```
 */
export function createProviderComposition(): ProviderCompositionBuilder<ProviderState0> {
  return ProviderCompositionBuilder.create();
}
