/**
 * @file
 * FlowDrop Playground Integration for Drupal
 *
 * @description
 * Provides Drupal behavior for initializing and managing the FlowDrop playground.
 * This script automatically mounts playground instances for elements with the
 * [data-flowdrop-playground] attribute.
 *
 * Supports three display modes:
 * - "standalone": Embedded in the page container (default)
 * - "embedded": Embedded with a close button
 * - "modal": Full-screen modal overlay (recommended for immersive experience)
 *
 * Requires the shared FlowDrop library (flowdrop_ui_components/flowdrop).
 *
 * @param {Function} once The "once" deduplication library.
 * @param {object} Drupal The Drupal API namespace.
 * @param {object} drupalSettings The Drupal settings object.
 */

((once, Drupal, drupalSettings) => {
  /**
   * Valid display modes for the playground
   *
   * @type {string[]}
   */
  const VALID_MODES = ['standalone', 'embedded', 'modal'];

  /**
   * Drupal behavior for mounting FlowDrop playground
   *
   * @type {object}
   */
  Drupal.behaviors.flowdropPlayground = {
    /**
     * Attach behavior to playground containers
     *
     * @param {HTMLElement} context - The context element to search within
     */
    attach(context) {
      once(
        'flowdrop-playground',
        '[data-flowdrop-playground]',
        context,
      ).forEach((playgroundContainer) => {
        initializePlayground(playgroundContainer);
      });
    },

    /**
     * Detach behavior and cleanup mounted components
     *
     * @param {HTMLElement} context - The context element to search within
     * @param {object} settings - Drupal settings object
     * @param {string} trigger - The trigger for detachment
     */
    detach(context, settings, trigger) {
      if (trigger !== 'unload') {
        return;
      }

      const containers = context.querySelectorAll('[data-flowdrop-playground]');
      containers.forEach((playgroundContainer) => {
        cleanupPlayground(playgroundContainer);
      });
    },
  };

  /**
   * Initialize the playground in the given container
   *
   * @param {HTMLElement} playgroundContainer - The container element for the playground
   */
  function initializePlayground(playgroundContainer) {
    if (playgroundContainer.dataset.flowdropInitialized === 'true') {
      return;
    }

    // Apply FlowDrop theme (light/dark/auto) to document so design-tokens
    // [data-theme="dark"] rules apply. Uses initializeSettings() which
    // internally calls initializeTheme() (initializeTheme is tree-shaken
    // from the bundle exports but initializeSettings is available).
    // Do NOT pass `defaults` — that path deep-merges over the user's
    // persisted preference and writes it back, clobbering their choice.
    if (
      typeof window.FlowDrop !== 'undefined' &&
      typeof window.FlowDrop.initializeSettings === 'function'
    ) {
      window.FlowDrop.initializeSettings();
    }

    // Check if shared FlowDrop library is available
    if (typeof window.FlowDrop === 'undefined') {
      showError(
        playgroundContainer,
        'FlowDrop Library Not Available',
        'The FlowDrop library could not be loaded. Please ensure flowdrop_ui_components module is enabled.',
      );
      return;
    }

    if (typeof window.FlowDrop.mountPlayground !== 'function') {
      showError(
        playgroundContainer,
        'Playground mount function not available',
        'The mountPlayground function is not available in the FlowDrop library.',
      );
      return;
    }

    // Parse workflow data
    const workflow =
      parseJsonData(playgroundContainer.dataset.workflow) ||
      drupalSettings.flowdrop?.workflow;

    // Parse endpoint configuration
    let endpointConfig =
      parseJsonData(playgroundContainer.dataset.endpointConfig) ||
      drupalSettings.flowdrop?.endpointConfig;

    if (!endpointConfig) {
      const baseUrl = drupalSettings.flowdrop?.apiBaseUrl || '/api/flowdrop';
      endpointConfig = createDefaultEndpointConfig(baseUrl);
    }

    // Get configuration from data attributes
    let mode = playgroundContainer.dataset.mode || 'standalone';
    const backUrl =
      playgroundContainer.dataset.backUrl || '/admin/flowdrop/workflows';
    const workflowName = playgroundContainer.dataset.workflowName || 'Workflow';
    const initialSessionId =
      playgroundContainer.dataset.initialSessionId ||
      drupalSettings.flowdrop?.initialSessionId ||
      null;

    // Chat input configuration options (new in FlowDrop 0.0.40).
    // showChatInput: Hide text input to show only Run button.
    // showRunButton: Hide Run button for view-only mode.
    // predefinedMessage: Custom message sent when Run is clicked.
    // autoRun: Auto-execute workflow on load.
    const showChatInput = playgroundContainer.dataset.showChatInput !== 'false';
    const showRunButton = playgroundContainer.dataset.showRunButton !== 'false';
    const predefinedMessage =
      playgroundContainer.dataset.predefinedMessage || null;
    const autoRun = playgroundContainer.dataset.autoRun === 'true';

    // Validate mode
    if (VALID_MODES.indexOf(mode) === -1) {
      mode = 'standalone';
    }

    // Clear loading state for non-modal modes
    if (mode !== 'modal') {
      // Loading element may be in the content container
      const contentContainer = playgroundContainer.querySelector(
        '.fd-playground__content',
      );
      const loadingElement = contentContainer
        ? contentContainer.querySelector('.fd-playground__loading')
        : playgroundContainer.querySelector('.fd-playground__loading');
      if (loadingElement) {
        loadingElement.style.display = 'none';
      }
    }

    // Mount the playground with the specified mode
    mountPlayground(playgroundContainer, {
      workflow,
      endpointConfig,
      mode,
      backUrl,
      workflowName,
      initialSessionId,
      showChatInput,
      showRunButton,
      predefinedMessage,
      autoRun,
    });
  }

  /**
   * Parse JSON data from a string, returning null on failure
   *
   * @param {string} jsonString - JSON string to parse
   * @return {object|null} Parsed object or null
   */
  function parseJsonData(jsonString) {
    if (!jsonString) return null;
    try {
      return JSON.parse(jsonString);
    } catch (error) {
      return null;
    }
  }

  /**
   * Mount the FlowDrop playground component
   *
   * @param {HTMLElement} container - The container element
   * @param {object} options - Mount options including mode, workflow, and endpointConfig
   */
  async function mountPlayground(container, options) {
    // Set initialized flag immediately to prevent duplicate initialization
    container.dataset.flowdropInitialized = 'true';
    try {
      // Extract workflow ID - this is required by mountPlayground
      const workflowId = options.workflow ? options.workflow.id : null;

      if (!workflowId) {
        throw new Error('Workflow ID is required');
      }

      // Prepare workflow data object (optional, for pre-populating data)
      const workflowData = options.workflow
        ? {
            id: options.workflow.id,
            name:
              options.workflow.label ||
              options.workflow.name ||
              'Untitled Workflow',
            description: options.workflow.description || '',
            nodes: options.workflow.nodes || [],
            edges: options.workflow.edges || [],
            metadata: {
              ...(options.workflow.metadata || {}),
              version: '1.0.0',
              created: options.workflow.created,
              changed: options.workflow.changed,
            },
          }
        : null;

      // Determine the display mode
      const mode = options.mode || 'standalone';
      const backUrl = options.backUrl || '/admin/flowdrop/workflows';

      /**
       * Close handler for modal and embedded modes.
       * Navigates to the back URL when the playground is closed.
       */
      const handleClose = () => {
        // Cleanup the playground instance
        cleanupPlayground(container);

        // Navigate to the back URL
        if (backUrl) {
          window.location.href = backUrl;
        }

        // Dispatch close event for custom handling
        container.dispatchEvent(
          new CustomEvent('flowdrop:playground:close', {
            detail: { containerId: container.id, workflowId },
            bubbles: true,
          }),
        );
      };

      // Build mount options based on mode
      const mountOptions = {
        workflowId,
        workflow: workflowData,
        endpointConfig: options.endpointConfig,
        mode,
        height: '100%',
        width: '100%',
        initialSessionId: options.initialSessionId || null,
        // Chat input configuration (FlowDrop 0.0.40+).
        // These options must be passed inside the config object.
        config: {
          showChatInput: options.showChatInput !== false,
          showRunButton: options.showRunButton !== false,
          predefinedMessage: options.predefinedMessage || null,
          autoRun: options.autoRun === true,
        },
        // Session status change callback (FlowDrop 0.0.61+).
        // Used to restart polling after interrupt resolution and
        // dispatch events for other Drupal behaviors.
        onSessionStatusChange(status, previousStatus) {
          handleSessionStatusChange(container, status, previousStatus);
        },
      };

      // Add onClose callback for modal and embedded modes
      if (mode === 'modal' || mode === 'embedded') {
        mountOptions.onClose = handleClose;
      }

      // Find the content container for mounting (supports header layout)
      // If a .fd-playground__content element exists, mount there to preserve the header
      const mountTarget =
        container.querySelector('.fd-playground__content') || container;

      // Mount the playground using the FlowDrop library
      const app = await window.FlowDrop.mountPlayground(
        mountTarget,
        mountOptions,
      );

      container.flowdropApp = app;

      container.dispatchEvent(
        new CustomEvent('flowdrop:playground:init', {
          detail: {
            containerId: container.id,
            app,
            workflowId,
            mode,
          },
          bubbles: true,
        }),
      );
    } catch (error) {
      // Clear initialization flag so retry is possible
      container.removeAttribute('data-flowdrop-initialized');
      showError(
        container,
        'Failed to load playground',
        `An error occurred while initializing the playground: ${error.message}`,
      );
    }
  }

  /**
   * Handle session status changes from the playground.
   *
   * Dispatches a custom event for other Drupal behaviors to react to,
   * and restarts polling when the workflow resumes after interrupt resolution.
   *
   * @param {HTMLElement} container - The playground container
   * @param {string} status - The new session status
   * @param {string} previousStatus - The previous session status
   */
  function handleSessionStatusChange(container, status, previousStatus) {
    const app = container.flowdropApp;
    if (!app) return;

    container.dispatchEvent(
      new CustomEvent('flowdrop:playground:status-change', {
        detail: { status, previousStatus },
        bubbles: true,
      }),
    );

    // Restart polling when workflow resumes after interrupt resolution.
    // The backend changes session status from awaiting_input → running when
    // an interrupt is resolved, but polling has already stopped. We need to
    // restart it so the UI picks up new messages.
    if (status === 'running' && previousStatus === 'awaiting_input') {
      app.startPolling();
    }
  }

  /**
   * Cleanup playground instance
   *
   * @param {HTMLElement} container - The playground container
   */
  function cleanupPlayground(container) {
    if (
      container.flowdropApp &&
      typeof container.flowdropApp.destroy === 'function'
    ) {
      container.flowdropApp.destroy();
      container.flowdropApp = null;
    }

    container.removeAttribute('data-flowdrop-initialized');
  }

  /**
   * Create default endpoint configuration
   *
   * @param {string} baseUrl - The base URL for API endpoints
   * @return {object} Default endpoint configuration
   */
  function createDefaultEndpointConfig(baseUrl) {
    return {
      baseUrl,
      endpoints: {
        nodes: {
          list: '/nodes',
          get: '/nodes/{id}',
          byCategory: '/nodes?category={category}',
          metadata: '/nodes/{id}/metadata',
        },
        workflows: {
          list: '/workflows',
          get: '/workflows/{id}',
          create: '/workflows',
          update: '/workflows/{id}',
          delete: '/workflows/{id}',
          validate: '/workflows/validate',
          export: '/workflows/{id}/export',
          import: '/workflows/import',
        },
        playground: {
          sessions: '/workflows/{id}/playground/sessions',
          session: '/playground/sessions/{sessionId}',
          messages: '/playground/sessions/{sessionId}/messages',
          stop: '/playground/sessions/{sessionId}/stop',
          reset: '/playground/sessions/{sessionId}/reset',
        },
        interrupts: {
          list: '/playground/sessions/{sessionId}/interrupts',
          get: '/interrupts/{interruptId}',
          resolve: '/interrupts/{interruptId}',
          cancel: '/interrupts/{interruptId}/cancel',
        },
      },
      timeout: 30000,
      retry: {
        enabled: true,
        maxAttempts: 3,
        delay: 1000,
        backoff: 'exponential',
      },
      auth: { type: 'none' },
    };
  }

  /**
   * Display an error message in the playground container
   *
   * @param {HTMLElement} container - The container element
   * @param {string} title - Error title
   * @param {string} message - Error message details
   */
  function showError(container, title, message) {
    const loadingElement = container.querySelector('.fd-playground__loading');
    if (loadingElement) {
      loadingElement.remove();
    }

    // Clear container safely
    while (container.firstChild) {
      container.removeChild(container.firstChild);
    }

    // Build error UI with safe DOM construction
    const errorDiv = document.createElement('div');
    errorDiv.className = 'fd-playground__error';
    errorDiv.setAttribute('role', 'alert');
    errorDiv.setAttribute('aria-live', 'assertive');

    const iconDiv = document.createElement('div');
    iconDiv.className = 'fd-playground__error-icon';
    const svgNS = 'http://www.w3.org/2000/svg';
    const svg = document.createElementNS(svgNS, 'svg');
    svg.setAttribute('xmlns', svgNS);
    svg.setAttribute('width', '48');
    svg.setAttribute('height', '48');
    svg.setAttribute('viewBox', '0 0 24 24');
    svg.setAttribute('fill', 'none');
    svg.setAttribute('stroke', 'currentColor');
    svg.setAttribute('stroke-width', '2');
    const circle = document.createElementNS(svgNS, 'circle');
    circle.setAttribute('cx', '12');
    circle.setAttribute('cy', '12');
    circle.setAttribute('r', '10');
    svg.appendChild(circle);
    const line1 = document.createElementNS(svgNS, 'line');
    line1.setAttribute('x1', '12');
    line1.setAttribute('y1', '8');
    line1.setAttribute('x2', '12');
    line1.setAttribute('y2', '12');
    svg.appendChild(line1);
    const line2 = document.createElementNS(svgNS, 'line');
    line2.setAttribute('x1', '12');
    line2.setAttribute('y1', '16');
    line2.setAttribute('x2', '12.01');
    line2.setAttribute('y2', '16');
    svg.appendChild(line2);
    iconDiv.appendChild(svg);
    errorDiv.appendChild(iconDiv);

    const h3 = document.createElement('h3');
    h3.className = 'fd-playground__error-title';
    h3.textContent = Drupal.checkPlain(title);
    errorDiv.appendChild(h3);

    const p = document.createElement('p');
    p.className = 'fd-playground__error-message';
    p.textContent = Drupal.checkPlain(message);
    errorDiv.appendChild(p);

    const hint = document.createElement('p');
    hint.className = 'fd-playground__error-hint';
    hint.textContent =
      'Please refresh the page or contact support if the problem persists.';
    errorDiv.appendChild(hint);

    container.appendChild(errorDiv);
    container.classList.add('fd-playground--error');
  }

  /**
   * Public API for FlowDrop Playground
   */
  Drupal.flowdropPlayground = {
    /**
     * Get the playground app instance
     *
     * @param {string|HTMLElement} idOrElement - Container ID or element
     * @return {object|null} The playground app instance or null
     */
    getApp(idOrElement) {
      const container =
        typeof idOrElement === 'string'
          ? document.getElementById(idOrElement)
          : idOrElement;
      return container?.flowdropApp || null;
    },

    /**
     * Destroy a playground instance
     *
     * @param {string|HTMLElement} idOrElement - Container ID or element
     */
    destroy(idOrElement) {
      const container =
        typeof idOrElement === 'string'
          ? document.getElementById(idOrElement)
          : idOrElement;
      if (container) {
        cleanupPlayground(container);
      }
    },

    /**
     * Open a playground in modal mode programmatically.
     * This creates a temporary container and mounts the playground as a full-screen modal.
     *
     * @param {object} options - Configuration options
     * @param {object} options.workflow - Workflow data object with id, nodes, edges, etc.
     * @param {object} options.endpointConfig - API endpoint configuration
     * @param {string} options.backUrl - URL to navigate to when modal is closed
     * @param {Function} options.onClose - Optional callback when modal is closed (called before navigation)
     * @return {Promise<object>} The mounted playground app instance
     */
    async openModal(options) {
      if (
        typeof window.FlowDrop === 'undefined' ||
        typeof window.FlowDrop.mountPlayground !== 'function'
      ) {
        throw new Error('FlowDrop library is not available');
      }

      if (!options.workflow || !options.workflow.id) {
        throw new Error('Workflow with id is required');
      }

      // Create a temporary container element for tracking
      const containerId = `flowdrop-playground-modal-${options.workflow.id}`;
      const existingContainer = document.getElementById(containerId);
      if (existingContainer) {
        // Close existing modal first
        cleanupPlayground(existingContainer);
        existingContainer.remove();
      }

      const container = document.createElement('div');
      container.id = containerId;
      container.setAttribute('data-flowdrop-playground', '');
      container.setAttribute('data-mode', 'modal');
      container.style.display = 'none'; // Hidden since modal mounts to body
      document.body.appendChild(container);

      // Prepare workflow data
      const workflowData = {
        id: options.workflow.id,
        name:
          options.workflow.label ||
          options.workflow.name ||
          'Untitled Workflow',
        description: options.workflow.description || '',
        nodes: options.workflow.nodes || [],
        edges: options.workflow.edges || [],
        metadata: options.workflow.metadata || {},
      };

      // Handle close action
      const handleClose = () => {
        // Call custom onClose callback if provided
        if (typeof options.onClose === 'function') {
          options.onClose();
        }

        // Cleanup
        cleanupPlayground(container);
        container.remove();

        // Navigate if backUrl is provided
        if (options.backUrl) {
          window.location.href = options.backUrl;
        }
      };

      // Mount in modal mode
      const app = await window.FlowDrop.mountPlayground(container, {
        workflowId: options.workflow.id,
        workflow: workflowData,
        endpointConfig: options.endpointConfig,
        mode: 'modal',
        onClose: handleClose,
      });

      container.dataset.flowdropInitialized = 'true';
      container.flowdropApp = app;

      return app;
    },
  };
})(once, Drupal, drupalSettings);
