// Auto-generated by DjangoCFG - see CLAUDE.md
/**
 * Django CFG API - API Client with JWT Management
 *
 * Usage:
 * ```typescript
 * import { API } from './api';
 *
 * const api = new API('https://api.example.com');
 *
 * // Set JWT token
 * api.setToken('your-jwt-token', 'refresh-token');
 *
 * // Use API
 * const posts = await api.posts.list();
 * const user = await api.users.retrieve(1);
 *
 * // Check authentication
 * if (api.isAuthenticated()) {
 *   // ...
 * }
 *
 * // Custom storage with logging (for Electron/Node.js)
 * import { MemoryStorageAdapter, APILogger } from './storage';
 * const logger = new APILogger({ enabled: true, logLevel: 'debug' });
 * const api = new API('https://api.example.com', {
 *   storage: new MemoryStorageAdapter(logger),
 *   loggerConfig: { enabled: true, logLevel: 'debug' }
 * });
 *
 * // Get OpenAPI schema
 * const schema = api.getSchema();
 * ```
 */

import { APIClient } from "./client";
import {
  StorageAdapter,
  LocalStorageAdapter,
  CookieStorageAdapter,
  MemoryStorageAdapter
} from "./storage";
import type { RetryConfig } from "./retry";
import type { LoggerConfig } from "./logger";
import { APILogger } from "./logger";
import { CentrifugoAdminApi } from "./centrifugo__centrifugo_admin_api/client";
import { CentrifugoAuth } from "./centrifugo__centrifugo_auth/client";
import { CentrifugoMonitoring } from "./centrifugo__centrifugo_monitoring/client";
import { CentrifugoTesting } from "./centrifugo__centrifugo_testing/client";
export * as CentrifugoAdminApiTypes from "./centrifugo__centrifugo_admin_api/models";
// Note: Direct exports (export * from) are removed to avoid duplicate type conflicts
// Use namespace exports like CfgAccountsTypes.User or import from specific modules
export * as CentrifugoAuthTypes from "./centrifugo__centrifugo_auth/models";
// Note: Direct exports (export * from) are removed to avoid duplicate type conflicts
// Use namespace exports like CfgAccountsTypes.User or import from specific modules
export * as CentrifugoMonitoringTypes from "./centrifugo__centrifugo_monitoring/models";
// Note: Direct exports (export * from) are removed to avoid duplicate type conflicts
// Use namespace exports like CfgAccountsTypes.User or import from specific modules
export * as CentrifugoTestingTypes from "./centrifugo__centrifugo_testing/models";
// Note: Direct exports (export * from) are removed to avoid duplicate type conflicts
// Use namespace exports like CfgAccountsTypes.User or import from specific modules

// Re-export Zod schemas for runtime validation
export * as Schemas from "./_utils/schemas";
// Also export all schemas directly for convenience
export * from "./_utils/schemas";

// Re-export Zod validation events for browser integration
export type { ValidationErrorDetail, ValidationErrorEvent } from "./validation-events";
export { dispatchValidationError, onValidationError, formatZodError } from "./validation-events";

// Re-export typed fetchers for universal usage
export * as Fetchers from "./_utils/fetchers";
export * from "./_utils/fetchers";

// Re-export API instance configuration functions
export {
  configureAPI,
  getAPIInstance,
  reconfigureAPI,
  clearAPITokens,
  resetAPI,
  isAPIConfigured
} from "./api-instance";
// NOTE: SWR hooks are generated in ./_utils/hooks/ but NOT exported here to keep
// the main bundle server-safe. Import hooks directly from the hooks directory:
//   import { useUsers } from './_utils/hooks';
// Or use a separate entry point like '@djangocfg/api/hooks' for client components.

// Re-export core client
export { APIClient };

// Re-export storage adapters for convenience
export type { StorageAdapter };
export { LocalStorageAdapter, CookieStorageAdapter, MemoryStorageAdapter };

// Re-export error classes for convenience
export { APIError, NetworkError } from "./errors";

// Re-export HTTP adapters for custom implementations
export type { HttpClientAdapter, HttpRequest, HttpResponse } from "./http";
export { FetchAdapter } from "./http";

// Re-export logger types and classes
export type { LoggerConfig, RequestLog, ResponseLog, ErrorLog } from "./logger";
export { APILogger } from "./logger";

// Re-export retry configuration and utilities
export type { RetryConfig, FailedAttemptInfo } from "./retry";
export { withRetry, shouldRetry, DEFAULT_RETRY_CONFIG } from "./retry";

export const TOKEN_KEY = "auth_token";
export const REFRESH_TOKEN_KEY = "refresh_token";

export interface APIOptions {
  /** Custom storage adapter (defaults to LocalStorageAdapter) */
  storage?: StorageAdapter;
  /** Retry configuration for failed requests */
  retryConfig?: RetryConfig;
  /** Logger configuration */
  loggerConfig?: Partial<LoggerConfig>;
}

export class API {
  private baseUrl: string;
  private _client: APIClient;
  private _token: string | null = null;
  private _refreshToken: string | null = null;
  private storage: StorageAdapter;
  private options?: APIOptions;

  // Sub-clients
  public centrifugo_admin_api!: CentrifugoAdminApi;
  public centrifugo_auth!: CentrifugoAuth;
  public centrifugo_monitoring!: CentrifugoMonitoring;
  public centrifugo_testing!: CentrifugoTesting;

  constructor(baseUrl: string, options?: APIOptions) {
    this.baseUrl = baseUrl;
    this.options = options;

    // Create logger if config provided
    const logger = options?.loggerConfig ? new APILogger(options.loggerConfig) : undefined;

    // Initialize storage with logger
    this.storage = options?.storage || new LocalStorageAdapter(logger);

    this._loadTokensFromStorage();

    // Initialize APIClient with token getter for URL authentication
    this._client = new APIClient(this.baseUrl, {
      retryConfig: this.options?.retryConfig,
      loggerConfig: this.options?.loggerConfig,
      tokenGetter: () => this.getToken(),
    });

    // Always inject auth header wrapper (reads token dynamically from storage)
    this._injectAuthHeader();

    // Initialize sub-clients from APIClient
    this.centrifugo_admin_api = this._client.centrifugo_admin_api;
    this.centrifugo_auth = this._client.centrifugo_auth;
    this.centrifugo_monitoring = this._client.centrifugo_monitoring;
    this.centrifugo_testing = this._client.centrifugo_testing;
  }

  private _loadTokensFromStorage(): void {
    this._token = this.storage.getItem(TOKEN_KEY);
    this._refreshToken = this.storage.getItem(REFRESH_TOKEN_KEY);
  }

  private _reinitClients(): void {
    this._client = new APIClient(this.baseUrl, {
      retryConfig: this.options?.retryConfig,
      loggerConfig: this.options?.loggerConfig,
      tokenGetter: () => this.getToken(),
    });

    // Always inject auth header wrapper (reads token dynamically from storage)
    this._injectAuthHeader();

    // Reinitialize sub-clients
    this.centrifugo_admin_api = this._client.centrifugo_admin_api;
    this.centrifugo_auth = this._client.centrifugo_auth;
    this.centrifugo_monitoring = this._client.centrifugo_monitoring;
    this.centrifugo_testing = this._client.centrifugo_testing;
  }

  private _injectAuthHeader(): void {
    // Override request method to inject auth header
    const originalRequest = this._client.request.bind(this._client);
    this._client.request = async <T>(
      method: string,
      path: string,
      options?: { params?: Record<string, any>; body?: any; formData?: FormData; headers?: Record<string, string> }
    ): Promise<T> => {
      // Read token from storage dynamically (supports JWT injection after instantiation)
      const token = this.getToken();
      const mergedOptions = {
        ...options,
        headers: {
          ...(options?.headers || {}),
          ...(token ? { 'Authorization': `Bearer ${token}` } : {}),
        },
      };

      return originalRequest(method, path, mergedOptions);
    };
  }

  /**
   * Get current JWT token
   */
  getToken(): string | null {
    return this.storage.getItem(TOKEN_KEY);
  }

  /**
   * Get current refresh token
   */
  getRefreshToken(): string | null {
    return this.storage.getItem(REFRESH_TOKEN_KEY);
  }

  /**
   * Set JWT token and refresh token
   * @param token - JWT access token
   * @param refreshToken - JWT refresh token (optional)
   */
  setToken(token: string, refreshToken?: string): void {
    this._token = token;
    this.storage.setItem(TOKEN_KEY, token);

    if (refreshToken) {
      this._refreshToken = refreshToken;
      this.storage.setItem(REFRESH_TOKEN_KEY, refreshToken);
    }

    // Reinitialize clients with new token
    this._reinitClients();
  }

  /**
   * Clear all tokens
   */
  clearTokens(): void {
    this._token = null;
    this._refreshToken = null;
    this.storage.removeItem(TOKEN_KEY);
    this.storage.removeItem(REFRESH_TOKEN_KEY);

    // Reinitialize clients without token
    this._reinitClients();
  }

  /**
   * Check if user is authenticated
   */
  isAuthenticated(): boolean {
    return !!this.getToken();
  }

  /**
   * Update base URL and reinitialize clients
   * @param url - New base URL
   */
  setBaseUrl(url: string): void {
    this.baseUrl = url;
    this._reinitClients();
  }

  /**
   * Get current base URL
   */
  getBaseUrl(): string {
    return this.baseUrl;
  }

  /**
   * Get OpenAPI schema path
   * @returns Path to the OpenAPI schema JSON file
   *
   * Note: The OpenAPI schema is available in the schema.json file.
   * You can load it dynamically using:
   * ```typescript
   * const schema = await fetch('./schema.json').then(r => r.json());
   * // or using fs in Node.js:
   * // const schema = JSON.parse(fs.readFileSync('./schema.json', 'utf-8'));
   * ```
   */
  getSchemaPath(): string {
    return './schema.json';
  }
}

export default API;