import React, { memo, useCallback, useState } from 'react';
import { Handle, Position, useConnection, useReactFlow, type NodeProps } from '@xyflow/react';
import {
  isStartNodeId,
  STRATEGY_CANDLE_TYPES,
  type HandleSide,
  type StrategyFlowNodeData,
} from '../../utils/strategyFlowLayout';
import { hasNodeSettings } from '../../utils/conditionPeriods';
import ConditionNodeSettings from './ConditionNodeSettings';

const LOGIC_COLORS: Record<string, string> = {
  AND: '#00aaff',
  OR: '#00d4ff',
  NOT: '#ffcc00',
};

const SIDES: { side: HandleSide; position: Position }[] = [
  { side: 'top', position: Position.Top },
  { side: 'right', position: Position.Right },
  { side: 'bottom', position: Position.Bottom },
  { side: 'left', position: Position.Left },
];

type ConnectHover = {
  handleId: string | null | undefined;
  handleType: 'source' | 'target';
  nodeId: string;
  isValid: boolean;
};

function MultiSideHandles({
  nodeId,
  sourceOnly = false,
  targetOnly = false,
  activeSourceSide = null,
  canSourceConnect = true,
  canTargetConnect = true,
}: {
  nodeId: string;
  sourceOnly?: boolean;
  targetOnly?: boolean;
  activeSourceSide?: HandleSide | null;
  canSourceConnect?: boolean;
  canTargetConnect?: boolean;
}) {
  const connectHover = useConnection((s): ConnectHover | null => {
    if (!s.inProgress || s.isValid === null || !s.toHandle) return null;
    return {
      nodeId: s.toHandle.nodeId,
      handleId: s.toHandle.id,
      handleType: s.toHandle.type,
      isValid: s.isValid,
    };
  });

  const hoverClass = (handleId: string, handleType: 'source' | 'target') => {
    if (!connectHover) return '';
    if (connectHover.nodeId !== nodeId || connectHover.handleType !== handleType) return '';
    if (connectHover.handleId !== handleId) return '';
    return connectHover.isValid ? ' se-flow-handle--valid-hover' : ' se-flow-handle--invalid';
  };

  return (
    <>
      {SIDES.map(({ side, position }) => (
        <React.Fragment key={side}>
          {!targetOnly && (
            <Handle
              type="source"
              position={position}
              id={`s-${side}`}
              isConnectable={canSourceConnect}
              className={`se-flow-handle se-flow-handle--src${
                !canSourceConnect ? ' se-flow-handle--disabled' : ''
              }${activeSourceSide === side && canSourceConnect ? ' se-flow-handle--active' : ''}${
                hoverClass(`s-${side}`, 'source')
              }`}
            />
          )}
          {!sourceOnly && (
            <Handle
              type="target"
              position={position}
              id={`t-${side}`}
              isConnectable={canTargetConnect}
              className={`se-flow-handle se-flow-handle--tgt${
                !canTargetConnect ? ' se-flow-handle--disabled' : ''
              }${hoverClass(`t-${side}`, 'target')}`}
            />
          )}
        </React.Fragment>
      ))}
    </>
  );
}

function usePaletteDropHandlers(id: string, d: StrategyFlowNodeData) {
  const { screenToFlowPosition } = useReactFlow();

  const onDragOver = useCallback((e: React.DragEvent) => {
    if (!e.dataTransfer.types.includes('application/json')) return;
    e.preventDefault();
    e.stopPropagation();
    e.dataTransfer.dropEffect = 'copy';
    const flowPos = screenToFlowPosition({ x: e.clientX, y: e.clientY });
    d.onDragOverTarget?.(id, flowPos);
  }, [d, id, screenToFlowPosition]);

  const onDragLeave = useCallback((e: React.DragEvent) => {
    e.stopPropagation();
    const rel = e.relatedTarget as Node | null;
    if (rel && e.currentTarget.contains(rel)) return;
    d.onDragLeaveTarget?.(id);
  }, [d, id]);

  const onDrop = useCallback((e: React.DragEvent) => {
    e.preventDefault();
    e.stopPropagation();
    try {
      const payload = JSON.parse(e.dataTransfer.getData('application/json'));
      const flowPos = screenToFlowPosition({ x: e.clientX, y: e.clientY });
      d.onDropTarget?.(id, payload, flowPos);
    } catch { /* ignore */ }
  }, [d, id, screenToFlowPosition]);

  return { onDragOver, onDragLeave, onDrop };
}

export const StartNode = memo(function StartNode({ id, data }: NodeProps) {
  const d = data as StrategyFlowNodeData;
  const isSell = d.signalTab === 'sell';
  const { onDragOver, onDragLeave, onDrop } = usePaletteDropHandlers(id, d);
  const candleType = d.candleType ?? '1m';
  const canDelete = id !== '__strategy_start__' && !!d.onDeleteStart;

  const stop = (e: React.SyntheticEvent) => e.stopPropagation();

  return (
    <div
      className={`se-flow-node se-flow-node--start${isSell ? ' se-flow-node--sell-mode' : ''} ${d.dragOver ? 'se-flow-node--drop' : ''}`}
      onDragOver={onDragOver}
      onDragLeave={onDragLeave}
      onDrop={onDrop}
    >
      <MultiSideHandles
        nodeId={id}
        sourceOnly
        activeSourceSide={d.activeSourceSide}
        canSourceConnect={d.canSourceConnect !== false}
      />
      <div className="se-flow-start-head">
        <div className="se-flow-start-dot" />
        <span className="se-flow-start-label">START</span>
        <select
          className="se-flow-start-tf"
          value={candleType}
          title="조건 판별 시간봉"
          onPointerDown={stop}
          onMouseDown={stop}
          onClick={stop}
          onChange={e => d.onStartCandleTypeChange?.(id, e.target.value)}
        >
          {STRATEGY_CANDLE_TYPES.map(ct => (
            <option key={ct} value={ct}>{ct}</option>
          ))}
        </select>
        {canDelete && (
          <button
            type="button"
            className="se-flow-del se-flow-del--start"
            title="START 삭제"
            onClick={e => {
              e.stopPropagation();
              d.onDeleteStart?.(id);
            }}
          >
            ×
          </button>
        )}
      </div>
    </div>
  );
});

export const LogicGateNode = memo(function LogicGateNode({ id, data, selected }: NodeProps) {
  const d = data as StrategyFlowNodeData;
  const node = d.logicNode!;
  const color = LOGIC_COLORS[node.type] ?? '#00aaff';
  const isSell = d.signalTab === 'sell';
  const { onDragOver, onDragLeave, onDrop } = usePaletteDropHandlers(id, d);

  return (
    <div
      className={`se-flow-node se-flow-node--logic${isSell ? ' se-flow-node--sell-mode' : ''}${d.isOrphan ? ' se-flow-node--orphan' : ''} ${selected ? 'se-flow-node--selected' : ''} ${d.dragOver ? 'se-flow-node--drop' : ''}`}
      style={{ '--se-gate-color': color } as React.CSSProperties}
      onDragOver={onDragOver}
      onDragLeave={onDragLeave}
      onDrop={onDrop}
    >
      <MultiSideHandles
        nodeId={id}
        activeSourceSide={d.activeSourceSide}
        canSourceConnect={d.canSourceConnect !== false}
        canTargetConnect={d.canTargetConnect !== false}
      />
      <div className="se-flow-gate-head">
        <span className="se-flow-gate-badge">[{node.type}]</span>
      </div>
      {(node.children ?? []).length === 0 && (
        <span className="se-flow-gate-hint">조건을 드롭하세요</span>
      )}
      <button type="button" className="se-flow-del" title="삭제" onClick={() => d.onDelete?.(id)}>×</button>
    </div>
  );
});

export const ConditionFlowNode = memo(function ConditionFlowNode({ id, data, selected }: NodeProps) {
  const d = data as StrategyFlowNodeData;
  const node = d.logicNode!;
  const cond = node.condition;
  const ind = cond?.indicatorType ?? 'COND';
  const condType = cond?.conditionType ?? '';
  const isCross = ['CROSS_UP', 'CROSS_DOWN'].includes(condType);
  const tone = isCross ? 'cross' : 'value';
  const isSell = d.signalTab === 'sell';
  const { onDragOver, onDragLeave, onDrop } = usePaletteDropHandlers(id, d);
  const [settingsOpen, setSettingsOpen] = useState(false);
  const showSettings = cond && hasNodeSettings(cond);

  const handleSettingsChange = useCallback((next: NonNullable<typeof cond>) => {
    d.onUpdateCondition?.(id, next);
  }, [d, id]);

  return (
    <div
      className={`se-flow-node se-flow-node--cond se-flow-node--${tone}${isSell ? ' se-flow-node--sell-mode' : ''}${d.isOrphan ? ' se-flow-node--orphan' : ''} ${selected ? 'se-flow-node--selected' : ''} ${d.dragOver ? 'se-flow-node--drop' : ''}${settingsOpen ? ' se-flow-node--settings-open' : ''}`}
      onDragOver={onDragOver}
      onDragLeave={onDragLeave}
      onDrop={onDrop}
    >
      <MultiSideHandles
        nodeId={id}
        targetOnly
        canTargetConnect={d.canTargetConnect !== false}
      />
      <div className="se-flow-cond-top">
        <div className="se-flow-cond-badge">{ind}</div>
        <div className="se-flow-cond-actions">
          {showSettings && (
            <button
              type="button"
              className="se-flow-settings"
              title="지표 설정"
              aria-label="지표 설정"
              onClick={e => {
                e.stopPropagation();
                setSettingsOpen(v => !v);
              }}
            >
              <svg width="12" height="12" 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="se-flow-del" title="삭제" onClick={() => d.onDelete?.(id)}>×</button>
        </div>
      </div>
      <div className="se-flow-cond-text">{d.label ?? ind}</div>
      {settingsOpen && cond && d.def && (
        <ConditionNodeSettings
          condition={cond}
          def={d.def}
          onChange={handleSettingsChange}
          onClose={() => setSettingsOpen(false)}
        />
      )}
    </div>
  );
});
