import { useCallback, useEffect, useRef, useState } from 'react';

const PANEL_HEIGHT_STORAGE_KEY = 'nodes_ui_flow_interactive_panel_height';
const DEFAULT_PANEL_HEIGHT = 320;
const MIN_PANEL_HEIGHT = 250;
const TOOLBAR_FALLBACK_HEIGHT = 72;
const MAX_PANEL_TOP_GAP = 8;

function getMaxPanelHeight() {
  if (typeof window === 'undefined') {
    return DEFAULT_PANEL_HEIGHT;
  }

  const toolbarHeight = document.querySelector('.toolbar')?.getBoundingClientRect().height || TOOLBAR_FALLBACK_HEIGHT;
  return Math.max(MIN_PANEL_HEIGHT, window.innerHeight - toolbarHeight - MAX_PANEL_TOP_GAP);
}

function readInitialPanelHeight() {
  if (typeof window === 'undefined') {
    return DEFAULT_PANEL_HEIGHT;
  }

  const savedHeight = Number(window.localStorage.getItem(PANEL_HEIGHT_STORAGE_KEY));
  if (!Number.isFinite(savedHeight)) {
    return DEFAULT_PANEL_HEIGHT;
  }

  return Math.min(Math.max(savedHeight, MIN_PANEL_HEIGHT), getMaxPanelHeight());
}

export default function InteractivePanel({
  isDemo,
  pendingQuestion,
  transcript,
  inputValue,
  isBusy,
  llmProvider,
  llmAutoAnswer,
  writeTranscriptLogs,
  llmRolePrompt,
  onInputChange,
  onLlmAutoAnswerChange,
  onWriteTranscriptLogsChange,
  onLlmRolePromptChange,
  onSubmitAnswer,
  onSimulateAnswer,
  onSaveSessionLog,
}) {
  const [panelHeight, setPanelHeight] = useState(readInitialPanelHeight);
  const canAnswer = Boolean(pendingQuestion) && !isBusy && inputValue.trim().length > 0;
  const canSimulate = Boolean(pendingQuestion) && !isBusy && llmRolePrompt.trim().length > 0;
  const providerLabel = {
    deepinfra: 'DeepInfra',
    ollama: 'Ollama',
  }[llmProvider] || llmProvider;
  const transcriptRef = useRef(null);
  const resizeRef = useRef(null);

  const clampPanelHeight = useCallback((height) => (
    Math.min(Math.max(Math.round(height), MIN_PANEL_HEIGHT), getMaxPanelHeight())
  ), []);

  useEffect(() => {
    if (transcriptRef.current) {
      transcriptRef.current.scrollTop = transcriptRef.current.scrollHeight;
    }
  }, [transcript]);

  useEffect(() => {
    if (isDemo) {
      return;
    }

    window.localStorage.setItem(PANEL_HEIGHT_STORAGE_KEY, String(panelHeight));
  }, [isDemo, panelHeight]);

  useEffect(() => {
    if (isDemo) {
      return undefined;
    }

    const handleResize = () => {
      setPanelHeight((currentHeight) => clampPanelHeight(currentHeight));
    };

    window.addEventListener('resize', handleResize);

    return () => {
      window.removeEventListener('resize', handleResize);
    };
  }, [clampPanelHeight, isDemo]);

  useEffect(() => () => {
    document.body.classList.remove('is-resizing-interactive-panel');
  }, []);

  const stopResize = useCallback((event) => {
    const resizeState = resizeRef.current;
    if (!resizeState || resizeState.pointerId !== event.pointerId) {
      return;
    }

    resizeRef.current = null;
    if (event.currentTarget.hasPointerCapture?.(event.pointerId)) {
      event.currentTarget.releasePointerCapture(event.pointerId);
    }
    document.body.classList.remove('is-resizing-interactive-panel');
  }, []);

  const handleResizeStart = useCallback((event) => {
    if (isDemo) {
      return;
    }

    if (event.button !== 0) {
      return;
    }

    event.preventDefault();
    resizeRef.current = {
      pointerId: event.pointerId,
      startY: event.clientY,
      startHeight: panelHeight,
    };
    event.currentTarget.setPointerCapture?.(event.pointerId);
    document.body.classList.add('is-resizing-interactive-panel');
  }, [isDemo, panelHeight]);

  const handleResizeMove = useCallback((event) => {
    if (isDemo) {
      return;
    }

    const resizeState = resizeRef.current;
    if (!resizeState || resizeState.pointerId !== event.pointerId) {
      return;
    }

    const nextHeight = resizeState.startHeight + resizeState.startY - event.clientY;
    setPanelHeight(clampPanelHeight(nextHeight));
  }, [clampPanelHeight, isDemo]);

  const handleResizeKeyDown = useCallback((event) => {
    if (isDemo) {
      return;
    }

    if (event.key !== 'ArrowUp' && event.key !== 'ArrowDown') {
      return;
    }

    event.preventDefault();
    const step = event.shiftKey ? 80 : 24;
    setPanelHeight((currentHeight) => (
      clampPanelHeight(currentHeight + (event.key === 'ArrowUp' ? step : -step))
    ));
  }, [clampPanelHeight, isDemo]);

  return (
    <section
      className={`interactive-panel ${isDemo ? 'interactive-panel--demo' : ''}`}
      style={isDemo ? undefined : { '--interactive-panel-height': `${panelHeight}px` }}
    >
      {!isDemo ? (
        <div
          className="interactive-panel__resize-handle"
          role="separator"
          aria-label="Изменить высоту интерактивной панели"
          aria-orientation="horizontal"
          tabIndex={0}
          onKeyDown={handleResizeKeyDown}
          onPointerDown={handleResizeStart}
          onPointerMove={handleResizeMove}
          onPointerUp={stopResize}
          onPointerCancel={stopResize}
        />
      ) : null}

      <div className="interactive-panel__main">
        <div className="interactive-panel__header">
          <div>
            <div className="interactive-panel__eyebrow">Интерактивный прогон</div>
            <div className="interactive-panel__title">
              {pendingQuestion ? pendingQuestion.question : 'Запустите сценарий, чтобы дойти до следующего вопроса.'}
            </div>
          </div>
          <div className={`interactive-panel__state ${pendingQuestion ? 'is-waiting' : ''}`}>
            {isBusy ? 'идет' : pendingQuestion ? 'ждем ответ' : 'готово'}
          </div>
        </div>

        <div className="interactive-panel__transcript" ref={transcriptRef}>
          {transcript.length === 0 ? (
            <div className="interactive-panel__empty">Диалог появится здесь во время интерактивного прогона.</div>
          ) : (
            transcript.map((message) => (
              <div key={message.id} className={`interactive-message interactive-message--${message.role}`}>
                <span>{message.role === 'assistant' ? 'Ассистент' : 'Пользователь'}</span>
                <p>{message.text}</p>
              </div>
            ))
          )}
        </div>

        <form className="interactive-panel__answer" onSubmit={onSubmitAnswer}>
          <input
            className="interactive-panel__input"
            type="text"
            value={inputValue}
            placeholder={pendingQuestion ? 'Введите ответ пользователя...' : 'Запустите сценарий до вопроса'}
            disabled={!pendingQuestion || isBusy}
            onChange={(event) => onInputChange(event.target.value)}
          />
          <button type="submit" className="toolbar__button toolbar__button--primary" disabled={!canAnswer}>
            Ответить
          </button>
        </form>
      </div>

      <aside className="interactive-panel__side">
        <button
          type="button"
          className="toolbar__button toolbar__button--primary interactive-panel__save-log"
          onClick={onSaveSessionLog}
        >
          Сохранить лог сессии
        </button>

        <div className="interactive-panel__tools">
          <button type="button" className="toolbar__button" disabled={!canSimulate} onClick={onSimulateAnswer}>
            Ответ LLM · {providerLabel}
          </button>
        </div>

        <div className="interactive-panel__tools">
          <label className="field-row">
            <input
              type="checkbox"
              checked={llmAutoAnswer}
              disabled={!llmRolePrompt.trim()}
              onChange={(event) => onLlmAutoAnswerChange(event.target.checked)}
            />
            <span>Автоответ LLM</span>
          </label>
          <label className="field-row">
            <input
              type="checkbox"
              checked={writeTranscriptLogs}
              onChange={(event) => onWriteTranscriptLogsChange(event.target.checked)}
            />
            <span>Писать txt-лог</span>
          </label>
        </div>

        <textarea
          className="interactive-panel__role"
          value={llmRolePrompt}
          disabled={isBusy}
          placeholder="Роль тестового пользователя..."
          onChange={(event) => onLlmRolePromptChange(event.target.value)}
        />
      </aside>
    </section>
  );
}
