import React, {
  Suspense,
  useCallback,
  useEffect,
  useMemo,
  useRef,
  useState,
} from 'react';
import { ChevronDown, ChevronUp } from 'lucide-react';
import {
  PanelPayload,
  PortfolioAction,
  PortfolioActionSeed,
  TerminalEntry,
} from '../../types/terminal';
import { PortfolioPanel } from '../Panels/PortfolioPanel';
import { NewsPanel } from '../Panels/NewsPanel';
import { AnalysisPanel } from '../Panels/AnalysisPanel';
import { ErrorPanel } from '../Panels/ErrorPanel';
import { FinancialsPanel } from '../Panels/FinancialsPanel';
import { BalanceSheetPanel } from '../Panels/BalanceSheetPanel';
import { CashFlowPanel } from '../Panels/CashFlowPanel';
import { DividendsPanel } from '../Panels/DividendsPanel';
import { EarningsPanel } from '../Panels/EarningsPanel';
import { FilingsPanel } from '../Panels/FilingsPanel';

const CompanyPanel = React.lazy(() =>
  import('../Panels/CompanyPanel').then((module) => ({
    default: module.CompanyPanel,
  })),
);

const MarkdownRenderer = React.lazy(() =>
  import('./MarkdownRenderer').then((module) => ({
    default: module.MarkdownRenderer,
  })),
);

interface TerminalOutputProps {
  workspaceId: string;
  history: TerminalEntry[];
  scrollTop: number;
  stickToBottom: boolean;
  collapsedThinkingEntryIds: string[];
  onScrollStateChange: (workspaceId: string, scrollState: {
    scrollTop: number;
    stickToBottom: boolean;
  }) => void;
  onToggleThinkingEntry: (workspaceId: string, entryId: string) => void;
  onRunCommand: (command: string) => void;
  onStartPortfolioAction: (
    action: PortfolioAction,
    seed?: PortfolioActionSeed,
  ) => void;
}

export const TerminalOutput: React.FC<TerminalOutputProps> = ({
  workspaceId,
  history,
  scrollTop,
  stickToBottom,
  collapsedThinkingEntryIds,
  onScrollStateChange,
  onToggleThinkingEntry,
  onRunCommand,
  onStartPortfolioAction,
}) => {
  const outputRef = useRef<HTMLDivElement | null>(null);
  const contentRef = useRef<HTMLDivElement | null>(null);
  const shouldStickToBottomRef = useRef(stickToBottom);
  const scrollFrameRef = useRef<number | null>(null);
  const [hasRestoredScroll, setHasRestoredScroll] = useState(false);
  const collapsedThinkingEntries = useMemo(
    () => new Set(collapsedThinkingEntryIds),
    [collapsedThinkingEntryIds],
  );

  const toggleThinkingEntry = useCallback((entryId: string) => {
    onToggleThinkingEntry(workspaceId, entryId);
  }, [onToggleThinkingEntry, workspaceId]);

  const isNearBottom = useCallback((element: HTMLDivElement) => {
    const distanceFromBottom =
      element.scrollHeight - element.scrollTop - element.clientHeight;
    return distanceFromBottom < 48;
  }, []);

  const scrollToBottom = useCallback(() => {
    const element = outputRef.current;
    if (!element || !shouldStickToBottomRef.current) {
      return;
    }

    requestAnimationFrame(() => {
      requestAnimationFrame(() => {
        element.scrollTop = element.scrollHeight;
      });
    });
  }, [outputRef]);

  useEffect(() => {
    shouldStickToBottomRef.current = stickToBottom;
  }, [stickToBottom]);

  useEffect(() => {
    setHasRestoredScroll(false);
  }, [workspaceId]);

  useEffect(() => {
    const element = outputRef.current;
    if (!element) {
      return;
    }

    const publishScrollState = () => {
      scrollFrameRef.current = null;
      const nextStickToBottom = isNearBottom(element);
      shouldStickToBottomRef.current = nextStickToBottom;
      onScrollStateChange(workspaceId, {
        scrollTop: element.scrollTop,
        stickToBottom: nextStickToBottom,
      });
    };

    const handleScroll = () => {
      if (scrollFrameRef.current !== null) {
        return;
      }

      scrollFrameRef.current = requestAnimationFrame(publishScrollState);
    };

    handleScroll();
    element.addEventListener('scroll', handleScroll);

    return () => {
      element.removeEventListener('scroll', handleScroll);
      if (scrollFrameRef.current !== null) {
        cancelAnimationFrame(scrollFrameRef.current);
        scrollFrameRef.current = null;
      }
    };
  }, [isNearBottom, onScrollStateChange, workspaceId]);

  useEffect(() => {
    const element = outputRef.current;
    if (!element || hasRestoredScroll) {
      return;
    }

    requestAnimationFrame(() => {
      element.scrollTop = shouldStickToBottomRef.current ? element.scrollHeight : scrollTop;
      setHasRestoredScroll(true);
    });
  }, [hasRestoredScroll, history, scrollTop]);

  useEffect(() => {
    scrollToBottom();
  }, [history, scrollToBottom]);

  useEffect(() => {
    const element = outputRef.current;
    const content = contentRef.current;
    if (!element || !content || typeof ResizeObserver === 'undefined') {
      return;
    }

    const observer = new ResizeObserver(() => {
      if (shouldStickToBottomRef.current) {
        element.scrollTop = element.scrollHeight;
      }
    });

    observer.observe(content);
    return () => observer.disconnect();
  }, [outputRef]);

  const renderPlainText = (content: string) => {
    const lines = content.split('\n');
    return (
      <div className="whitespace-pre-wrap break-words font-mono text-[14px] leading-relaxed">
        {lines.map((line, i) => (
          <div key={i} className="break-words">{line || '\u00A0'}</div>
        ))}
      </div>
    );
  };

  const renderMarkdown = (content: string) => (
    <Suspense fallback={renderPlainText(content)}>
      <MarkdownRenderer content={content} />
    </Suspense>
  );

  const renderContent = (entry: TerminalEntry) => {
    if (typeof entry.content !== 'string') {
      return null;
    }

    if (entry.renderMode === 'markdown') {
      return renderMarkdown(entry.content);
    }

    return renderPlainText(entry.content);
  };

  const getEntryColor = (type: TerminalEntry['type']) => {
    switch (type) {
      case 'command':
        return 'text-term-text';
      case 'response':
        return 'text-info';
      case 'system':
        return 'text-term-text-tertiary italic';
      case 'thinking':
        return 'text-term-text-muted';
      case 'error':
        return 'text-negative';
      case 'panel':
        return '';
      default:
        return 'text-term-text';
    }
  };

  const getEntrySpacing = (type: TerminalEntry['type']) => {
    // Context-aware spacing based on entry type
    switch (type) {
      case 'panel':
        return 'mb-6'; // More space for panels
      case 'command':
        return 'mb-2'; // Less space after commands
      case 'error':
        return 'mb-4'; // Moderate space for errors
      case 'thinking':
        return 'mb-3';
      default:
        return 'mb-3'; // Default space
    }
  };

  const shouldShowTimestamp = (entry: TerminalEntry) => {
    // Only show timestamps for commands and errors, not for panels
    return entry.type === 'command' || entry.type === 'error';
  };

  const getAnimationDelay = (type: TerminalEntry['type']) => {
    // Faster animation for panels, slower for text
    switch (type) {
      case 'panel':
        return 'duration-150';
      case 'command':
        return 'duration-200';
      default:
        return 'duration-200';
    }
  };

  const renderPanel = (entry: TerminalEntry) => {
    if (entry.type !== 'panel' || typeof entry.content === 'string') {
      return null;
    }

    const panelData = entry.content as PanelPayload;

    switch (panelData.type) {
      case 'company':
        return (
          <Suspense fallback={null}>
            <CompanyPanel company={panelData.data} />
          </Suspense>
        );
      case 'error':
        return <ErrorPanel error={panelData.data} />;
      case 'portfolio':
        return (
          <PortfolioPanel
            portfolio={panelData.data}
            onRunCommand={onRunCommand}
            onStartAction={onStartPortfolioAction}
            onSelectHolding={(symbol) => onRunCommand(`/search ${symbol}`)}
          />
        );
      case 'news':
        return (
          <NewsPanel
            news={panelData.data}
            ticker={panelData.ticker}
            onRunCommand={onRunCommand}
          />
        );
      case 'analysis':
        return <AnalysisPanel analysis={panelData.data} />;
      case 'financials':
        return <FinancialsPanel data={panelData.data} />;
      case 'balanceSheet':
        return <BalanceSheetPanel data={panelData.data} onRunCommand={onRunCommand} />;
      case 'cashFlow':
        return <CashFlowPanel data={panelData.data} onRunCommand={onRunCommand} />;
      case 'dividends':
        return <DividendsPanel data={panelData.data} />;
      case 'earnings':
        return <EarningsPanel data={panelData.data} onRunCommand={onRunCommand} />;
      case 'filings':
        return <FilingsPanel data={panelData.data} onRunCommand={onRunCommand} />;
      default:
        return null;
    }
  };

  const getPreviewText = (content: string, maxLength: number = 50): string => {
    const trimmed = content.trim();
    if (trimmed.length <= maxLength) return trimmed;
    return trimmed.slice(0, maxLength).trim() + '...';
  };

  const renderThinkingContent = (entry: TerminalEntry) => {
    if (typeof entry.content !== 'string') return null;

    return (
      <Suspense fallback={renderPlainText(entry.content)}>
        <MarkdownRenderer content={entry.content} variant="thinking" />
      </Suspense>
    );
  };

  return (
    <div
      ref={outputRef}
      className="min-h-0 min-w-0 flex-1 overflow-x-hidden overflow-y-auto px-6 py-4"
      style={{
        scrollbarWidth: 'thin',
        scrollbarColor: 'var(--term-border) var(--term-bg-elevated)'
      }}
    >
      <div ref={contentRef} className="min-w-0 break-words">
        {history.map((entry) => (
          <div
            key={entry.id}
            className={`animate-in fade-in slide-in-from-bottom-2 ${getAnimationDelay(entry.type)} ${getEntrySpacing(entry.type)}`}
          >
            {/* Entry Header */}
            {entry.type === 'command' && (
              <div className="flex items-start gap-2">
                <span className="text-info font-mono select-none">{'>'}</span>
                <div className={getEntryColor(entry.type)}>
                  {renderContent(entry)}
                </div>
              </div>
            )}

            {entry.type === 'thinking' && (
              <div className="rounded-lg border border-term-border bg-term-surface/70 overflow-hidden">
                {/* Header - Always Visible */}
                <button
                  type="button"
                  onClick={() => toggleThinkingEntry(entry.id)}
                  className="w-full flex items-center justify-between gap-2 px-3 py-2 text-left transition-colors hover:bg-term-highlight/50"
                >
                  <div className="flex items-center gap-2 min-w-0 flex-1">
                    <span className="text-[10px] font-mono uppercase tracking-[0.24em] text-term-text-tertiary flex-shrink-0">
                      Thinking
                    </span>
                    {collapsedThinkingEntries.has(entry.id) && typeof entry.content === 'string' && (
                      <span className="text-[11px] text-term-text-muted truncate">
                        {getPreviewText(entry.content, 50)}
                      </span>
                    )}
                  </div>
                  <div className="flex-shrink-0 text-term-text-tertiary">
                    {collapsedThinkingEntries.has(entry.id) ? (
                      <ChevronDown className="h-3.5 w-3.5" />
                    ) : (
                      <ChevronUp className="h-3.5 w-3.5" />
                    )}
                  </div>
                </button>

                {/* Collapsible Content */}
                <div
                  className={`transition-[grid-template-rows] duration-300 ease-in-out ${
                    collapsedThinkingEntries.has(entry.id) ? 'grid-rows-[0fr]' : 'grid-rows-[1fr]'
                  }`}
                  style={{ display: 'grid' }}
                >
                  <div className="overflow-hidden">
                    <div className="px-3 pb-3">
                      {renderThinkingContent(entry)}
                    </div>
                  </div>
                </div>
              </div>
            )}

            {entry.type !== 'command' &&
              entry.type !== 'panel' &&
              entry.type !== 'thinking' && (
                <div className={getEntryColor(entry.type)}>
                  {renderContent(entry)}
                </div>
              )}

            {/* Render Panel */}
            {entry.type === 'panel' && renderPanel(entry)}

            {/* Timestamp - Selective display */}
            {entry.timestamp && shouldShowTimestamp(entry) && (
              <div className="mt-1 text-[10px] font-mono text-term-text-tertiary">
                {entry.timestamp.toLocaleTimeString('en-US', { hour12: false })}
              </div>
            )}
          </div>
        ))}

        {/* Empty State */}
        {history.length === 0 && (
          <div className="py-20 text-center font-mono text-term-text-muted">
            <div className="mb-4 text-4xl">⚡</div>
            <div>Terminal ready. Type a command or load /portfolio to open portfolio tools.</div>
          </div>
        )}
      </div>
    </div>
  );
};
