import React, { useCallback, useState } from 'react';
import type { LogicNode } from '../../utils/strategyTypes';
import {
  CondEditor,
  addChild,
  makeNode,
  mergeAtRoot,
  nodeToText,
  type DefType,
} from '../../utils/strategyEditorShared';
import { hasNodeSettings } from '../../utils/conditionPeriods';
import ConditionNodeSettings from './ConditionNodeSettings';
import {
  type EditorConditionState,
  addExtraStartSection,
  updateBranchRoot,
  updateStartCandleType,
  removeStartSection,
  collectStartSections,
} from '../../utils/strategyConditionSerde';
import { STRATEGY_CANDLE_TYPES } from '../../utils/strategyStartNodes';

const NODE_COLORS: Record<string, string> = {
  AND: '#4caf50',
  OR: '#2196f3',
  NOT: '#ff9800',
};
const IND_COLOR = '#9c27b0';
const LIST_DROP_KEY = '__list__';

interface TreeNodeProps {
  node: LogicNode;
  signalType: 'buy' | 'sell';
  onUpdate: (n: LogicNode) => void;
  onDelete: () => void;
  onDropOnNode?: (targetId: string, data: { type: string; value: string; label: string; composite?: boolean }) => void;
  dragOverKey?: string | null;
  setDragOverKey?: (key: string | null) => void;
  dropScope: string;
  depth?: number;
  def: DefType;
  onAddStart?: () => void;
}

const TreeNodeComp: React.FC<TreeNodeProps> = ({
  node,
  signalType,
  onUpdate,
  onDelete,
  onDropOnNode,
  dragOverKey,
  setDragOverKey,
  dropScope,
  depth = 0,
  def,
  onAddStart,
}) => {
  const isLogic = ['AND', 'OR', 'NOT'].includes(node.type);
  const color = isLogic ? NODE_COLORS[node.type] : IND_COLOR;
  const nodeDropKey = `${dropScope}:${node.id}`;
  const [settingsOpen, setSettingsOpen] = useState(false);
  const showSettings = node.type === 'CONDITION' && node.condition && hasNodeSettings(node.condition);
  const label = node.type === 'CONDITION' && node.condition
    ? nodeToText(node, def)
    : node.type === 'AND'
      ? 'AND (그리고)'
      : node.type === 'OR'
        ? 'OR (또는)'
        : 'NOT (반대)';

  const handleDragOver = (e: React.DragEvent) => {
    if (!isLogic) return;
    e.preventDefault();
    e.stopPropagation();
    setDragOverKey?.(nodeDropKey);
  };
  const handleDragLeave = () => setDragOverKey?.(null);
  const handleDrop = (e: React.DragEvent) => {
    if (!isLogic) return;
    e.preventDefault();
    e.stopPropagation();
    setDragOverKey?.(null);
    try {
      const data = JSON.parse(e.dataTransfer.getData('application/json'));
      if (data.type === 'start') {
        onAddStart?.();
        return;
      }
      onDropOnNode?.(node.id, data);
    } catch {
      /* ignore */
    }
  };

  const handleCondChange = (c: NonNullable<LogicNode['condition']>) => onUpdate({ ...node, condition: c });
  const handleChildUpdate = (childId: string, updated: LogicNode) =>
    onUpdate({ ...node, children: (node.children ?? []).map(c => (c.id === childId ? updated : c)) });
  const handleChildDelete = (childId: string) =>
    onUpdate({ ...node, children: (node.children ?? []).filter(c => c.id !== childId) });

  return (
    <div
      className={`sp-tree-node${dragOverKey === nodeDropKey ? ' sp-tree-node--over' : ''}`}
      style={{ marginLeft: depth > 0 ? 12 : 0 }}
      onDragOver={handleDragOver}
      onDragLeave={handleDragLeave}
      onDrop={handleDrop}
    >
      <div className="sp-node-head sp-node-head--cond" style={{ borderLeftColor: color }}>
        <span className="sp-node-badge" style={{ background: color }}>
          {node.type === 'CONDITION' && node.condition ? node.condition.indicatorType : node.type}
        </span>
        <span className="sp-node-label">{label}</span>
        <div className="sp-node-actions">
          {showSettings && (
            <button
              type="button"
              className="sp-node-settings"
              title="지표 설정"
              aria-label="지표 설정"
              aria-expanded={settingsOpen}
              onClick={e => {
                e.stopPropagation();
                setSettingsOpen(v => !v);
              }}
            >
              <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
                <circle cx="12" cy="12" r="3"/>
                <path d="M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42"/>
              </svg>
            </button>
          )}
          <button type="button" className="sp-node-del" title="삭제" onClick={onDelete}>✕</button>
        </div>
        {settingsOpen && node.condition && (
          <ConditionNodeSettings
            condition={node.condition}
            def={def}
            onChange={handleCondChange}
            onClose={() => setSettingsOpen(false)}
            popoverClassName="sp-node-settings-pop"
          />
        )}
      </div>

      {node.type === 'CONDITION' && node.condition && (
        <CondEditor cond={node.condition} signalType={signalType} onChange={handleCondChange} def={def} />
      )}

      {isLogic && (
        <div className="sp-node-children">
          {(node.children ?? []).map(child => (
            <TreeNodeComp
              key={child.id}
              node={child}
              signalType={signalType}
              onUpdate={u => handleChildUpdate(child.id, u)}
              onDelete={() => handleChildDelete(child.id)}
              onDropOnNode={onDropOnNode}
              dragOverKey={dragOverKey}
              setDragOverKey={setDragOverKey}
              dropScope={dropScope}
              depth={depth + 1}
              def={def}
              onAddStart={onAddStart}
            />
          ))}
          {dragOverKey === nodeDropKey && (
            <div className="sp-drop-hint-inner">여기에 드롭하세요</div>
          )}
        </div>
      )}
    </div>
  );
};

interface StartSectionBlockProps {
  startId: string;
  candleType: string;
  root: LogicNode | null;
  canDelete: boolean;
  signalTab: 'buy' | 'sell';
  def: DefType;
  dragOverKey: string | null;
  setDragOverKey: (key: string | null) => void;
  onRootChange: (root: LogicNode | null) => void;
  onCandleTypeChange: (candleType: string) => void;
  onDeleteStart?: () => void;
  onAddStart?: () => void;
}

function StartSectionBlock({
  startId,
  candleType,
  root,
  canDelete,
  signalTab,
  def,
  dragOverKey,
  setDragOverKey,
  onRootChange,
  onCandleTypeChange,
  onDeleteStart,
  onAddStart,
}: StartSectionBlockProps) {
  const sectionDropKey = `${startId}:__root__`;

  const applyDrop = useCallback((
    targetId: string | null,
    data: { type: string; value: string; label: string; composite?: boolean },
  ) => {
    if (data.type === 'start') {
      onAddStart?.();
      return;
    }
    const newNode = makeNode(data.type, data.value, signalTab, def, data.composite ? { composite: true } : undefined);
    if (!root) {
      onRootChange(newNode);
      return;
    }
    if (!targetId) {
      onRootChange(mergeAtRoot(root, newNode, data.type === 'operator'));
      return;
    }
    onRootChange(addChild(root, targetId, newNode));
  }, [root, signalTab, def, onRootChange, onAddStart]);

  const handleSectionDrop = (e: React.DragEvent) => {
    e.preventDefault();
    e.stopPropagation();
    setDragOverKey(null);
    try {
      const data = JSON.parse(e.dataTransfer.getData('application/json'));
      applyDrop(null, data);
    } catch {
      /* ignore */
    }
  };

  const handleDropOnNode = (targetId: string, data: { type: string; value: string; label: string; composite?: boolean }) => {
    applyDrop(targetId, data);
  };

  return (
    <section className="sp-start-section">
      <header className="sp-start-head">
        <span className="sp-start-dot" aria-hidden />
        <span className="sp-start-label">START</span>
        <select
          className="sp-start-tf"
          value={candleType}
          title="조건 판별 시간봉"
          onChange={e => onCandleTypeChange(e.target.value)}
        >
          {STRATEGY_CANDLE_TYPES.map(ct => (
            <option key={ct} value={ct}>{ct}</option>
          ))}
        </select>
        {canDelete && (
          <button type="button" className="sp-start-del" title="START 삭제" onClick={onDeleteStart}>×</button>
        )}
      </header>

      <div
        className={`sp-start-body${dragOverKey === sectionDropKey ? ' sp-start-body--over' : ''}`}
        onDragOver={e => {
          e.preventDefault();
          e.stopPropagation();
          setDragOverKey(sectionDropKey);
        }}
        onDragLeave={() => setDragOverKey(null)}
        onDrop={handleSectionDrop}
      >
        {!root ? (
          <div className="sp-drop-empty sp-drop-empty--section">
            논리 연산자·지표를 드래그하여 [{candleType}] 조건을 구성하세요.
          </div>
        ) : (
          <TreeNodeComp
            node={root}
            signalType={signalTab}
            onUpdate={onRootChange}
            onDelete={() => onRootChange(null)}
            onDropOnNode={handleDropOnNode}
            dragOverKey={dragOverKey}
            setDragOverKey={setDragOverKey}
            dropScope={startId}
            def={def}
            onAddStart={onAddStart}
          />
        )}
      </div>
    </section>
  );
}

interface Props {
  editorState: EditorConditionState;
  signalTab: 'buy' | 'sell';
  def: DefType;
  onEditorStateChange: (next: EditorConditionState) => void;
  onAddStart?: () => void;
  onOrphansChange?: (nodes: LogicNode[]) => void;
  orphans?: LogicNode[];
}

export default function StrategyListEditor({
  editorState,
  signalTab,
  def,
  onEditorStateChange,
  onAddStart,
  onOrphansChange,
  orphans = [],
}: Props) {
  const [dragOverKey, setDragOverKey] = useState<string | null>(null);
  const sections = collectStartSections(editorState);

  const handleAddStart = useCallback(() => {
    if (onAddStart) {
      onAddStart();
      return;
    }
    onEditorStateChange(addExtraStartSection(editorState));
  }, [onAddStart, onEditorStateChange, editorState]);

  const handleRootChange = useCallback((startId: string, root: LogicNode | null) => {
    onEditorStateChange(updateBranchRoot(editorState, startId, root));
  }, [editorState, onEditorStateChange]);

  const handleCandleTypeChange = useCallback((startId: string, candleType: string) => {
    onEditorStateChange(updateStartCandleType(editorState, startId, candleType));
  }, [editorState, onEditorStateChange]);

  const handleDeleteStart = useCallback((startId: string) => {
    const { state, orphanedNodes } = removeStartSection(editorState, startId);
    onEditorStateChange(state);
    if (orphanedNodes.length && onOrphansChange) {
      onOrphansChange([...orphans, ...orphanedNodes]);
    }
  }, [editorState, onEditorStateChange, onOrphansChange, orphans]);

  const handleListDragOver = (e: React.DragEvent) => {
    e.preventDefault();
    e.dataTransfer.dropEffect = 'copy';
    setDragOverKey(LIST_DROP_KEY);
  };

  const handleListDrop = (e: React.DragEvent) => {
    e.preventDefault();
    e.stopPropagation();
    setDragOverKey(null);
    try {
      const data = JSON.parse(e.dataTransfer.getData('application/json'));
      if (data.type === 'start') {
        handleAddStart();
      }
    } catch {
      /* ignore */
    }
  };

  return (
    <div
      className={`se-list-editor sp-dropzone${dragOverKey === LIST_DROP_KEY ? ' se-list-editor--over' : ''}`}
      onDragOver={handleListDragOver}
      onDragLeave={() => setDragOverKey(null)}
      onDrop={handleListDrop}
    >
      {sections.map(section => (
        <StartSectionBlock
          key={section.startId}
          startId={section.startId}
          candleType={section.candleType}
          root={section.root}
          canDelete={section.canDelete}
          signalTab={signalTab}
          def={def}
          dragOverKey={dragOverKey}
          setDragOverKey={setDragOverKey}
          onRootChange={root => handleRootChange(section.startId, root)}
          onCandleTypeChange={ct => handleCandleTypeChange(section.startId, ct)}
          onDeleteStart={section.canDelete ? () => handleDeleteStart(section.startId) : undefined}
          onAddStart={handleAddStart}
        />
      ))}
      {sections.length === 0 && (
        <div className="sp-drop-empty">
          START를 이 영역에 드래그하거나 우측 패널에서 추가하세요.
        </div>
      )}
    </div>
  );
}
