import React, { useState, useEffect } from 'react';
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
import { materialLight } from 'react-syntax-highlighter/dist/esm/styles/prism';

// Import react-json-view with error handling
const ReactJsonView = React.lazy(() => import('react-json-view').catch(() => ({
  default: () => <div className="messages messages--error">Failed to load JSON viewer component</div>
})));

// Import react-json-view-lite with error handling
const ReactJsonViewLite = React.lazy(() => import('react-json-view-lite').then(module => ({
  default: module.JsonView
})).catch(() => ({
  default: () => <div className="messages messages--error">Failed to load alternate JSON viewer component</div>
})));

// Import the CSS from react-json-view-lite
import 'react-json-view-lite/dist/index.css';

const FallbackComponent = () => (
  <div className="form-item" style={{ padding: '16px', textAlign: 'center' }}>
    <div className="spinner" style={{ display: 'inline-block', marginRight: '8px' }}></div>
    <span>Loading JSON viewer…</span>
  </div>
);

function ResponseDisplay({ response, responseHeaders, onCopyJson, onCopyPath }) {
  const [useAlternateViewer, setUseAlternateViewer] = useState(false);
  const [viewerError, setViewerError] = useState(false);
  const [activeTab, setActiveTab] = useState('body');
  const [contentType, setContentType] = useState('json');
  const [responseSize, setResponseSize] = useState(0);
  const [viewMode, setViewMode] = useState('pretty'); // 'pretty' or 'raw'
  const [headersViewMode, setHeadersViewMode] = useState('pretty'); // 'pretty' or 'raw'

  // Detect response content type and size when response changes
  useEffect(() => {
    if (response) {
      // Determine content type based on response or headers
      detectContentType();

      // Calculate response size
      calculateResponseSize();
    }
  }, [response, responseHeaders]);

  // Determine content type from response and headers
  const detectContentType = () => {
    // Default to JSON
    let detectedType = 'json';

    // Check Content-Type header if available
    if (responseHeaders && responseHeaders['content-type']) {
      const contentTypeHeader = responseHeaders['content-type'].toLowerCase();

      if (contentTypeHeader.includes('application/json') ||
          contentTypeHeader.includes('application/vnd.api+json')) {
        detectedType = 'json';
      } else if (contentTypeHeader.includes('text/html')) {
        detectedType = 'html';
      } else if (contentTypeHeader.includes('text/plain')) {
        detectedType = 'text';
      } else if (contentTypeHeader.includes('text/xml') ||
                contentTypeHeader.includes('application/xml')) {
        detectedType = 'xml';
      } else if (contentTypeHeader.includes('image/')) {
        detectedType = 'image';
      }
    }

    // If no content type header or response is not an object, try to detect from content
    if (response !== null && response !== undefined) {
      if (typeof response !== 'object') {
        // If response is a string, try to detect its format
        if (typeof response === 'string') {
          if (response.trim().startsWith('<') && (
              response.includes('<!DOCTYPE html') ||
              response.includes('<html'))) {
            detectedType = 'html';
          } else if (response.trim().startsWith('<') &&
                    (response.includes('<?xml') ||
                     response.includes('</'))) {
            detectedType = 'xml';
          } else {
            detectedType = 'text';
          }
        }
      } else if (response && typeof response === 'object') {
        // All object responses are treated as JSON
        detectedType = 'json';
      }
    }

    setContentType(detectedType);
  };

  // Calculate response size
  const calculateResponseSize = () => {
    try {
      if (response === null || response === undefined) {
        setResponseSize(0);
        return;
      }

      if (typeof response === 'object') {
        const jsonSize = JSON.stringify(response).length;
        setResponseSize(jsonSize);
      } else if (typeof response === 'string') {
        setResponseSize(response.length);
      } else {
        setResponseSize(String(response).length);
      }
    } catch (err) {
      console.error('Error calculating response size:', err);
      setResponseSize(0);
    }
  };

  // Safe stringification of any object, with error handling
  const safeStringify = (obj) => {
    if (obj === null || obj === undefined) {
      return 'null';
    }

    try {
      return JSON.stringify(obj, null, 2);
    } catch (err) {
      console.error('Error stringifying object:', err);
      return String(obj);
    }
  };

  // Error boundary for JSON viewer
  const handleJsonViewError = () => {
    if (!useAlternateViewer) {
      setUseAlternateViewer(true);
    } else {
      setViewerError(true);
    }
  };

  // Render different content based on type
  const renderContent = () => {
    // Handle undefined or null response
    if (response === null || response === undefined) {
      return (
        <div className="form-item__description" style={{ padding: '16px' }}>
          No response data available
        </div>
      );
    }

    switch (contentType) {
      case 'json':
        return renderJsonContent();

      case 'html':
        return renderHtmlContent();

      case 'xml':
        return renderXmlContent();

      case 'image':
        return renderImageContent();

      case 'text':
      default:
        return renderTextContent();
    }
  };

  // Safe rendering of the JSON response data
  const renderJsonContent = () => {
    // If raw view mode is selected, render the raw JSON
    if (viewMode === 'raw') {
      const jsonString = typeof response === 'object'
        ? safeStringify(response)
        : typeof response === 'string' ? response : String(response);

      return (
        <div className="form-element">
          <SyntaxHighlighter
            language="json"
            style={materialLight}
            wrapLines={true}
            customStyle={{
              margin: 0,
              fontSize: '0.85rem',
              padding: '12px',
            }}
          >
            {jsonString}
          </SyntaxHighlighter>
        </div>
      );
    }

    // For pretty mode, handle non-object responses that were classified as JSON
    if (typeof response !== 'object') {
      try {
        // Try to parse it as JSON string
        const parsedJson = JSON.parse(response);
        return renderJsonViewer(parsedJson);
      } catch (err) {
        // If parsing fails, render as text
        return renderTextContent();
      }
    }

    return renderJsonViewer(response);
  };

  // Render the appropriate JSON viewer
  const renderJsonViewer = (jsonData) => {
    // Get JSON string for size check and fallback
    const jsonString = safeStringify(jsonData);

    // If we've tried both viewers and they failed, fall back to syntax highlighter
    if (viewerError || responseSize > 500000) {
      return (
        <div className="form-element">
          <SyntaxHighlighter
            language="json"
            style={materialLight}
            wrapLines={true}
            customStyle={{
              margin: 0,
              fontSize: '0.8rem',
              maxHeight: '400px',
              overflow: 'auto',
              padding: '12px',
            }}
          >
            {jsonString}
          </SyntaxHighlighter>
        </div>
      );
    }

    // No JSON:API info banner
    const jsonApiInfo = null;

    // Use the primary or alternate JSON viewer based on state
    try {
      if (!useAlternateViewer) {
        return (
          <React.Suspense fallback={<FallbackComponent />}>
            <div style={{ padding: '10px' }}>
              {jsonApiInfo}
              <div className="json-view-container">
                <ReactJsonView
                  src={jsonData}
                  collapsed={2}
                  displayDataTypes={false}
                  displayObjectSize={true}
                  enableClipboard={false}
                  name={null}
                  theme="rjv-default"
                  onError={handleJsonViewError}
                />
              </div>
            </div>
          </React.Suspense>
        );
      } else {
        return (
          <React.Suspense fallback={<FallbackComponent />}>
            <div style={{ padding: '10px' }}>
              {jsonApiInfo}
              <div className="json-view-container">
                <ReactJsonViewLite
                  data={jsonData}
                  shouldExpandNode={(level) => level < 2}
                />
              </div>
            </div>
          </React.Suspense>
        );
      }
    } catch (err) {
      console.error('Error rendering JsonView:', err);
      handleJsonViewError();

      // Final fallback to syntax highlighter
      return (
        <div className="form-element">
          <SyntaxHighlighter
            language="json"
            style={materialLight}
            wrapLines={true}
            customStyle={{
              margin: 0,
              fontSize: '0.85rem',
              maxHeight: '400px',
              overflow: 'auto',
              padding: '12px',
            }}
          >
            {jsonString}
          </SyntaxHighlighter>
        </div>
      );
    }
  };

  // Render HTML content with syntax highlighting
  const renderHtmlContent = () => {
    const htmlContent = typeof response === 'string' ? response : String(response);

    return (
      <div className="form-element">
        <SyntaxHighlighter
          language="html"
          style={materialLight}
          wrapLines={true}
          customStyle={{
            margin: 0,
            fontSize: '0.85rem',
            padding: '12px',
          }}
        >
          {htmlContent}
        </SyntaxHighlighter>
      </div>
    );
  };

  // Render XML content with syntax highlighting
  const renderXmlContent = () => {
    const xmlContent = typeof response === 'string' ? response : String(response);

    return (
      <div className="form-element">
        <SyntaxHighlighter
          language="xml"
          style={materialLight}
          wrapLines={true}
          customStyle={{
            margin: 0,
            fontSize: '0.85rem',
            padding: '12px',
          }}
        >
          {xmlContent}
        </SyntaxHighlighter>
      </div>
    );
  };

  // Render text content with syntax highlighting
  const renderTextContent = () => {
    const textContent = typeof response === 'string' ? response : String(response);

    return (
      <div className="form-element">
        <SyntaxHighlighter
          language="text"
          style={materialLight}
          wrapLines={true}
          customStyle={{
            margin: 0,
            fontSize: '0.85rem',
            padding: '12px',
          }}
        >
          {textContent}
        </SyntaxHighlighter>
      </div>
    );
  };

  // Render image content
  const renderImageContent = () => {
    // Try to render as image if we have a base64 string or URL
    let imgSrc = '';

    if (typeof response === 'string') {
      if (response.startsWith('data:image/')) {
        imgSrc = response;
      } else if (response.startsWith('http')) {
        imgSrc = response;
      }
    }

    if (imgSrc) {
      return (
        <div style={{ padding: '16px', textAlign: 'center' }}>
          <img src={imgSrc} alt="Response" style={{ maxWidth: '100%' }} />
        </div>
      );
    }

    // If we can't render as image, fall back to text
    return renderTextContent();
  };

  // Handle copy operations safely
  const handleCopy = () => {
    if (!onCopyJson) return;

    try {
      onCopyJson();
    } catch (err) {
      console.error('Error in copy handler:', err);
    }
  };

  // Handle copying headers
  const handleCopyHeaders = () => {
    if (!responseHeaders) return;

    try {
      // Create a formatted string of headers
      let headerText;

      if (headersViewMode === 'raw') {
        // Raw JSON format
        headerText = JSON.stringify(responseHeaders, null, 2);
      } else {
        // Pretty format with name: value pairs
        headerText = Object.entries(responseHeaders)
          .map(([name, value]) => `${name}: ${value}`)
          .join('\n');
      }

      navigator.clipboard.writeText(headerText).then(() => {
        // You could show a small notification here if desired
        console.log('Headers copied to clipboard');
      });
    } catch (err) {
      console.error('Error copying headers:', err);
    }
  };

  // Render response headers as a formatted table
  const renderHeaders = () => {
    if (!responseHeaders) {
      return (
        <div className="form-item__description" style={{ padding: '16px' }}>
          No response headers available
        </div>
      );
    }

    // If raw view is selected, just show the JSON representation
    if (headersViewMode === 'raw') {
      return (
        <div className="form-element">
          <SyntaxHighlighter
            language="json"
            style={materialLight}
            wrapLines={true}
            customStyle={{
              margin: 0,
              fontSize: '0.85rem',
              padding: '12px',
            }}
          >
            {JSON.stringify(responseHeaders, null, 2)}
          </SyntaxHighlighter>
        </div>
      );
    }

    // For pretty view, render the organized table
    // Convert headers object to array for display
    const headerEntries = Object.entries(responseHeaders);

    // Group headers by category for better organization
    const categories = {
      'Cache control': ['cache-control', 'etag', 'expires', 'last-modified', 'age', 'x-drupal-dynamic-cache', 'x-drupal-cache'],
      'Content': ['content-type', 'content-length', 'content-encoding', 'content-language'],
      'CORS': ['access-control-allow-origin', 'access-control-allow-methods', 'access-control-allow-headers', 'access-control-expose-headers'],
      'General': []
    };

    // Categorize headers
    const categorizedHeaders = {};
    headerEntries.forEach(([name, value]) => {
      let assigned = false;
      for (const [category, headerNames] of Object.entries(categories)) {
        if (headerNames.some(h => name.toLowerCase().includes(h))) {
          if (!categorizedHeaders[category]) categorizedHeaders[category] = [];
          categorizedHeaders[category].push([name, value]);
          assigned = true;
          break;
        }
      }

      if (!assigned) {
        if (!categorizedHeaders['General']) categorizedHeaders['General'] = [];
        categorizedHeaders['General'].push([name, value]);
      }
    });

    return (
      <div style={{ padding: '8px' }} data-testid="headers-display">
        {Object.entries(categorizedHeaders).map(([category, headers]) => (
          headers.length > 0 && (
            <div key={category} style={{ marginBottom: '16px' }}>
              <h3 style={{
                fontSize: '0.9rem',
                fontWeight: '600',
                color: 'var(--gin-color-text)',
                marginBottom: '8px',
                paddingBottom: '4px',
                borderBottom: '1px solid var(--gin-border-color-form-element)'
              }}>
                {category}
              </h3>
              <table style={{ width: '100%', borderCollapse: 'collapse' }}>
                <tbody>
                  {headers.map(([name, value]) => (
                    <tr key={name} style={{ borderBottom: '1px solid var(--explorer-border-light, #eee)' }}>
                      <td style={{
                        padding: '8px',
                        fontWeight: 'bold',
                        verticalAlign: 'top',
                        width: '30%',
                        color: 'var(--gin-color-text)'
                      }}>
                        {name}
                      </td>
                      <td style={{
                        padding: '8px',
                        wordBreak: 'break-word',
                        fontFamily: 'monospace',
                        fontSize: '0.9em',
                        color: 'var(--gin-color-text-light)'
                      }}>
                        {value}
                      </td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
          )
        ))}
      </div>
    );
  };

  // Render content type badge
  const renderContentTypeBadge = () => {
    if (!response) return null;

    const badges = {
      'json': { label: 'JSON', color: 'var(--gin-color-primary, #003cc5)', bg: 'var(--gin-color-primary-light, #e6f6ff)' },
      'html': { label: 'HTML', color: 'var(--gin-color-warning, #974e00)', bg: 'var(--gin-color-warning-light, #fff3d3)' },
      'xml': { label: 'XML', color: 'var(--gin-color-warning, #974e00)', bg: 'var(--gin-color-warning-light, #fff3d3)' },
      'text': { label: 'Text', color: 'var(--gin-color-text, #222330)', bg: 'var(--gin-color-disabled, #f3f4f9)' },
      'image': { label: 'Image', color: 'var(--gin-color-green, #42802c)', bg: 'var(--gin-color-green-light, #d1e6a1)' }
    };

    const badge = badges[contentType] || badges.text;

    return (
      <span style={{
        display: 'inline-block',
        padding: '2px 8px',
        borderRadius: '12px',
        fontSize: '0.75rem',
        fontWeight: 'bold',
        backgroundColor: badge.bg,
        color: badge.color,
        marginLeft: '8px'
      }}>
        {badge.label}
      </span>
    );
  };

  // Helper function to render the toggle button set
  const renderToggleButtons = (currentMode, setModeFunc) => {
    return (
      <div className="toggle-wrapper" style={{ marginRight: '10px' }}>
        <div
          className="toggle-buttons"
          style={{
            display: 'flex',
            borderRadius: '4px',
            overflow: 'hidden',
            border: '1px solid var(--gin-border-color-form-element)',
          }}
        >
          <button
            className={`button button--small ${currentMode === 'pretty' ? 'is-active' : ''}`}
            onClick={() => setModeFunc('pretty')}
            style={{
              padding: '4px 8px',
              margin: 0,
              fontSize: '0.7rem',
              backgroundColor: currentMode === 'pretty' ?
                'var(--gin-color-primary-hover)' : 'var(--gin-bg-app)',
              color: currentMode === 'pretty' ?
                'white' : 'var(--gin-color-text)',
              borderRadius: 0,
              border: 'none',
              borderRight: '1px solid var(--gin-border-color-form-element)',
            }}
          >
            Pretty
          </button>
          <button
            className={`button button--small ${currentMode === 'raw' ? 'is-active' : ''}`}
            onClick={() => setModeFunc('raw')}
            style={{
              padding: '4px 8px',
              margin: 0,
              fontSize: '0.7rem',
              backgroundColor: currentMode === 'raw' ?
                'var(--gin-color-primary-hover)' : 'var(--gin-bg-app)',
              color: currentMode === 'raw' ?
                'white' : 'var(--gin-color-text)',
              borderRadius: 0,
              border: 'none',
            }}
          >
            Raw
          </button>
        </div>
      </div>
    );
  };

  return (
    <div className="response-display" data-testid="response-display">
      {/* Response tabs - styled like the query builder tabs */}
      <div className="query-panel-tabs" style={{ marginBottom: '0' }}>
        <button
          className={`query-panel-tab ${activeTab === 'body' ? 'active' : ''}`}
          onClick={() => setActiveTab('body')}
        >
          Body
        </button>
        <button
          className={`query-panel-tab ${activeTab === 'headers' ? 'active' : ''}`}
          onClick={() => setActiveTab('headers')}
        >
          Headers {responseHeaders && `(${Object.keys(responseHeaders).length})`}
        </button>

        {/* Body tab toolbar */}
        {activeTab === 'body' && response && (
          <div style={{ marginLeft: 'auto', display: 'flex', alignItems: 'center' }}>
            {contentType === 'json' && renderToggleButtons(viewMode, setViewMode)}
            <button
              className="button button--small"
              onClick={handleCopy}
              style={{ marginRight: '8px', alignSelf: 'center' }}
              aria-label="Copy response to clipboard"
              data-testid="format-toggle-button"
            >
              Copy
            </button>
          </div>
        )}

        {/* Headers tab toolbar */}
        {activeTab === 'headers' && responseHeaders && (
          <div style={{ marginLeft: 'auto', display: 'flex', alignItems: 'center' }}>
            {renderToggleButtons(headersViewMode, setHeadersViewMode)}
            <button
              className="button button--small"
              onClick={handleCopyHeaders}
              style={{ marginRight: '8px', alignSelf: 'center' }}
              aria-label="Copy headers to clipboard"
            >
              Copy
            </button>
          </div>
        )}
      </div>

      {/* Tab content */}
      <div style={{
        maxHeight: '580px',
        overflow: 'auto',
        backgroundColor: 'var(--gin-bg-layer, white)',
        border: '1px solid var(--explorer-border)',
        borderRadius: '4px',
      }}>
        <div style={{ padding: '0' }}>
          {activeTab === 'body' ? (
            response === null || response === undefined ? (
              <div className="form-item__description" style={{ padding: '16px' }}>
                No requests have been made yet
              </div>
            ) : (
              renderContent()
            )
          ) : (
            renderHeaders()
          )}
        </div>
      </div>
    </div>
  );
}

export default ResponseDisplay;
