import { useEffect, useState } from "react";
import { Implementation } from "@modelcontextprotocol/sdk/types.js";
import { Client } from "@modelcontextprotocol/sdk/client";
import { App, McpUiAppCapabilities, PostMessageTransport } from "../app";
export * from "../app";

/**
 * Options for configuring the {@link useApp} hook.
 *
 * Note: This interface does NOT expose {@link App} options like `autoResize`.
 * The hook creates the `App` with default options (`autoResize: true`). If you
 * need custom `App` options, create the `App` manually instead of using this hook.
 *
 * @see {@link useApp} for the hook that uses these options
 * @see {@link useAutoResize} for manual auto-resize control with custom `App` options
 */
export interface UseAppOptions {
  /** App identification (name and version) */
  appInfo: Implementation;
  /**
   * Declares what features this app supports.
   */
  capabilities: McpUiAppCapabilities;
  /**
   * Called after {@link App} is created but before connection.
   *
   * Use this to register request/notification handlers that need to be in place
   * before the initialization handshake completes.
   *
   * @param app - The newly created `App` instance
   *
   * @example Register a notification handler
   * ```typescript
   * import { McpUiToolInputNotificationSchema } from '@modelcontextprotocol/ext-apps/react';
   *
   * onAppCreated: (app) => {
   *   app.setNotificationHandler(
   *     McpUiToolInputNotificationSchema,
   *     (notification) => {
   *       console.log("Tool input:", notification.params.arguments);
   *     }
   *   );
   * }
   * ```
   */
  onAppCreated?: (app: App) => void;
}

/**
 * State returned by the {@link useApp} hook.
 */
export interface AppState {
  /** The connected {@link App} instance, null during initialization */
  app: App | null;
  /** Whether initialization completed successfully */
  isConnected: boolean;
  /** Connection error if initialization failed, null otherwise */
  error: Error | null;
}

/**
 * React hook to create and connect an MCP App.
 *
 * This hook manages {@link App} creation and connection. It automatically
 * creates a {@link PostMessageTransport} to window.parent and handles
 * initialization.
 *
 * This hook is part of the optional React integration. The core SDK (`App`,
 * `PostMessageTransport`) is framework-agnostic and can be used with any UI
 * framework or vanilla JavaScript.
 *
 * **Important**: The hook intentionally does NOT re-run when options change
 * to avoid reconnection loops. Options are only used during the initial mount.
 * Furthermore, the `App` instance is NOT closed on unmount. This avoids cleanup
 * issues during React Strict Mode's double-mount cycle. If you need to
 * explicitly close the `App`, call {@link App.close} manually.
 *
 * @param options - Configuration for the app
 * @returns Current connection state and app instance. If connection fails during
 *   initialization, the `error` field will contain the error (typically connection
 *   timeouts, initialization handshake failures, or transport errors).
 *
 * @example Basic usage
 * ```typescript
 * import { useApp, McpUiToolInputNotificationSchema } from '@modelcontextprotocol/ext-apps/react';
 *
 * function MyApp() {
 *   const { app, isConnected, error } = useApp({
 *     appInfo: { name: "MyApp", version: "1.0.0" },
 *     capabilities: {},
 *     onAppCreated: (app) => {
 *       // Register handlers before connection
 *       app.setNotificationHandler(
 *         McpUiToolInputNotificationSchema,
 *         (notification) => {
 *           console.log("Tool input:", notification.params.arguments);
 *         }
 *       );
 *     },
 *   });
 *
 *   if (error) return <div>Error: {error.message}</div>;
 *   if (!isConnected) return <div>Connecting...</div>;
 *   return <div>Connected!</div>;
 * }
 * ```
 *
 * @see {@link App.connect} for the underlying connection method
 * @see {@link useAutoResize} for manual auto-resize control when using custom App options
 */
export function useApp({
  appInfo,
  capabilities,
  onAppCreated,
}: UseAppOptions): AppState {
  const [app, setApp] = useState<App | null>(null);
  const [isConnected, setIsConnected] = useState(false);
  const [error, setError] = useState<Error | null>(null);

  useEffect(() => {
    let mounted = true;

    async function connect() {
      try {
        const transport = new PostMessageTransport(
          window.parent,
          window.parent,
        );
        const app = new App(appInfo, capabilities);

        // Register handlers BEFORE connecting
        onAppCreated?.(app);

        await app.connect(transport);

        if (mounted) {
          setApp(app);
          setIsConnected(true);
          setError(null);
        }
      } catch (error) {
        if (mounted) {
          setApp(null);
          setIsConnected(false);
          setError(
            error instanceof Error ? error : new Error("Failed to connect"),
          );
        }
      }
    }

    connect();

    return () => {
      mounted = false;
    };
  }, []); // Intentionally not including options to avoid reconnection

  return { app, isConnected, error };
}
