/**
 * NodeConfigPanelV2 - Configuration panel for AtomizerSpec v2.0 nodes
 * 
 * This component uses useSpecStore instead of the legacy useCanvasStore.
 * It renders type-specific configuration forms based on the selected node.
 */

import { useState, useMemo, useCallback } from 'react';
import { Microscope, Trash2, X, AlertCircle } from 'lucide-react';
import {
  useSpecStore,
  useSpec,
  useSelectedNodeId,
  useSelectedNode,
} from '../../../hooks/useSpecStore';
import { FileBrowser } from './FileBrowser';
import { IntrospectionPanel } from './IntrospectionPanel';
import {
  DesignVariable,
  Extractor,
  Objective,
  Constraint,
} from '../../../types/atomizer-spec';

// Common input class for dark theme
const inputClass = "w-full px-3 py-2 bg-dark-800 border border-dark-600 text-white placeholder-dark-400 rounded-lg focus:border-primary-500 focus:outline-none transition-colors";
const selectClass = "w-full px-3 py-2 bg-dark-800 border border-dark-600 text-white rounded-lg focus:border-primary-500 focus:outline-none transition-colors";
const labelClass = "block text-sm font-medium text-dark-300 mb-1";

interface NodeConfigPanelV2Props {
  /** Called when panel should close */
  onClose?: () => void;
}

export function NodeConfigPanelV2({ onClose }: NodeConfigPanelV2Props) {
  const spec = useSpec();
  const selectedNodeId = useSelectedNodeId();
  const selectedNode = useSelectedNode();
  const { updateNode, removeNode, clearSelection } = useSpecStore();
  
  const [showFileBrowser, setShowFileBrowser] = useState(false);
  const [showIntrospection, setShowIntrospection] = useState(false);
  const [isUpdating, setIsUpdating] = useState(false);
  const [error, setError] = useState<string | null>(null);

  // Determine node type from ID prefix or from the node itself
  const nodeType = useMemo(() => {
    if (!selectedNodeId) return null;
    
    // Synthetic nodes have fixed IDs
    if (selectedNodeId === 'model') return 'model';
    if (selectedNodeId === 'solver') return 'solver';
    if (selectedNodeId === 'algorithm') return 'algorithm';
    if (selectedNodeId === 'surrogate') return 'surrogate';
    
    // Real nodes have prefixed IDs
    const prefix = selectedNodeId.split('_')[0];
    switch (prefix) {
      case 'dv': return 'designVar';
      case 'ext': return 'extractor';
      case 'obj': return 'objective';
      case 'con': return 'constraint';
      default: return null;
    }
  }, [selectedNodeId]);

  // Get label for display
  const nodeLabel = useMemo(() => {
    if (!selectedNodeId || !spec) return 'Node';
    
    switch (nodeType) {
      case 'model': return spec.meta.study_name || 'Model';
      case 'solver': return spec.model.sim?.solution_type || 'Solver';
      case 'algorithm': return spec.optimization.algorithm?.type || 'Algorithm';
      case 'surrogate': return 'Neural Surrogate';
      default:
        if (selectedNode) {
          return (selectedNode as any).name || selectedNodeId;
        }
        return selectedNodeId;
    }
  }, [selectedNodeId, selectedNode, nodeType, spec]);

  // Handle field changes
  const handleChange = useCallback(async (field: string, value: unknown) => {
    if (!selectedNodeId || !selectedNode) return;
    
    setIsUpdating(true);
    setError(null);
    
    try {
      await updateNode(selectedNodeId, { [field]: value });
    } catch (err) {
      console.error('Failed to update node:', err);
      setError(err instanceof Error ? err.message : 'Update failed');
    } finally {
      setIsUpdating(false);
    }
  }, [selectedNodeId, selectedNode, updateNode]);

  // Handle delete
  const handleDelete = useCallback(async () => {
    if (!selectedNodeId) return;
    
    // Synthetic nodes can't be deleted
    if (['model', 'solver', 'algorithm', 'surrogate'].includes(selectedNodeId)) {
      setError('This node cannot be deleted');
      return;
    }
    
    setIsUpdating(true);
    setError(null);
    
    try {
      await removeNode(selectedNodeId);
      clearSelection();
      onClose?.();
    } catch (err) {
      console.error('Failed to delete node:', err);
      setError(err instanceof Error ? err.message : 'Delete failed');
    } finally {
      setIsUpdating(false);
    }
  }, [selectedNodeId, removeNode, clearSelection, onClose]);

  // Don't render if no node selected
  if (!selectedNodeId || !spec) {
    return null;
  }

  // Check if this is a synthetic node (model, solver, algorithm, surrogate)
  const isSyntheticNode = ['model', 'solver', 'algorithm', 'surrogate'].includes(selectedNodeId);

  return (
    <div className="w-80 bg-dark-850 border-l border-dark-700 flex flex-col h-full">
      {/* Header */}
      <div className="flex justify-between items-center p-4 border-b border-dark-700">
        <h3 className="font-semibold text-white truncate flex-1">
          Configure {nodeLabel}
        </h3>
        <div className="flex items-center gap-2">
          {!isSyntheticNode && (
            <button
              onClick={handleDelete}
              disabled={isUpdating}
              className="p-1.5 text-red-400 hover:text-red-300 hover:bg-red-500/10 rounded transition-colors"
              title="Delete node"
            >
              <Trash2 size={16} />
            </button>
          )}
          {onClose && (
            <button
              onClick={onClose}
              className="p-1.5 text-dark-400 hover:text-white hover:bg-dark-700 rounded transition-colors"
              title="Close panel"
            >
              <X size={16} />
            </button>
          )}
        </div>
      </div>

      {/* Error display */}
      {error && (
        <div className="mx-4 mt-4 p-3 bg-red-500/10 border border-red-500/30 rounded-lg flex items-start gap-2">
          <AlertCircle size={16} className="text-red-400 flex-shrink-0 mt-0.5" />
          <p className="text-sm text-red-400 flex-1">{error}</p>
          <button onClick={() => setError(null)} className="text-red-400 hover:text-red-300">
            <X size={14} />
          </button>
        </div>
      )}

      {/* Content */}
      <div className="flex-1 overflow-y-auto p-4">
        <div className="space-y-4">
          {/* Loading indicator */}
          {isUpdating && (
            <div className="text-xs text-primary-400 animate-pulse">Updating...</div>
          )}

          {/* Model node (synthetic) */}
          {nodeType === 'model' && spec.model && (
            <ModelNodeConfig spec={spec} />
          )}

          {/* Solver node (synthetic) */}
          {nodeType === 'solver' && (
            <SolverNodeConfig spec={spec} />
          )}

          {/* Algorithm node (synthetic) */}
          {nodeType === 'algorithm' && (
            <AlgorithmNodeConfig spec={spec} />
          )}

          {/* Surrogate node (synthetic) */}
          {nodeType === 'surrogate' && (
            <SurrogateNodeConfig spec={spec} />
          )}

          {/* Design Variable */}
          {nodeType === 'designVar' && selectedNode && (
            <DesignVarNodeConfig 
              node={selectedNode as DesignVariable} 
              onChange={handleChange}
            />
          )}

          {/* Extractor */}
          {nodeType === 'extractor' && selectedNode && (
            <ExtractorNodeConfig 
              node={selectedNode as Extractor} 
              onChange={handleChange}
            />
          )}

          {/* Objective */}
          {nodeType === 'objective' && selectedNode && (
            <ObjectiveNodeConfig 
              node={selectedNode as Objective} 
              onChange={handleChange}
            />
          )}

          {/* Constraint */}
          {nodeType === 'constraint' && selectedNode && (
            <ConstraintNodeConfig 
              node={selectedNode as Constraint} 
              onChange={handleChange}
            />
          )}
        </div>
      </div>

      {/* File Browser Modal */}
      <FileBrowser
        isOpen={showFileBrowser}
        onClose={() => setShowFileBrowser(false)}
        onSelect={() => {
          // This would update the model path - but model is synthetic
          setShowFileBrowser(false);
        }}
        fileTypes={['.sim', '.prt', '.fem', '.afem']}
      />

      {/* Introspection Panel */}
      {showIntrospection && spec.model.sim?.path && (
        <div className="fixed top-20 right-96 z-40">
          <IntrospectionPanel
            filePath={spec.model.sim.path}
            onClose={() => setShowIntrospection(false)}
          />
        </div>
      )}
    </div>
  );
}

// ============================================================================
// Type-specific configuration components
// ============================================================================

interface SpecConfigProps {
  spec: NonNullable<ReturnType<typeof useSpec>>;
}

function ModelNodeConfig({ spec }: SpecConfigProps) {
  const [showIntrospection, setShowIntrospection] = useState(false);
  
  return (
    <>
      <div>
        <label className={labelClass}>Model File</label>
        <input
          type="text"
          value={spec.model.sim?.path || ''}
          readOnly
          className={`${inputClass} font-mono text-sm bg-dark-900 cursor-not-allowed`}
          title="Model path is read-only. Change via study configuration."
        />
        <p className="text-xs text-dark-500 mt-1">Read-only. Set in study configuration.</p>
      </div>
      
      <div>
        <label className={labelClass}>Solver Type</label>
        <input
          type="text"
          value={spec.model.sim?.solution_type || 'Not detected'}
          readOnly
          className={`${inputClass} bg-dark-900 cursor-not-allowed`}
        />
      </div>

      {spec.model.sim?.path && (
        <button
          onClick={() => setShowIntrospection(true)}
          className="w-full flex items-center justify-center gap-2 px-3 py-2.5 bg-primary-500/20
                     hover:bg-primary-500/30 border border-primary-500/30 rounded-lg
                     text-primary-400 text-sm font-medium transition-colors"
        >
          <Microscope size={16} />
          Introspect Model
        </button>
      )}

      {showIntrospection && spec.model.sim?.path && (
        <div className="fixed top-20 right-96 z-40">
          <IntrospectionPanel
            filePath={spec.model.sim.path}
            onClose={() => setShowIntrospection(false)}
          />
        </div>
      )}
    </>
  );
}

function SolverNodeConfig({ spec }: SpecConfigProps) {
  return (
    <div>
      <label className={labelClass}>Solution Type</label>
      <input
        type="text"
        value={spec.model.sim?.solution_type || 'Not configured'}
        readOnly
        className={`${inputClass} bg-dark-900 cursor-not-allowed`}
        title="Solver type is determined by the model file."
      />
      <p className="text-xs text-dark-500 mt-1">Detected from model file.</p>
    </div>
  );
}

function AlgorithmNodeConfig({ spec }: SpecConfigProps) {
  const algo = spec.optimization.algorithm;
  
  return (
    <>
      <div>
        <label className={labelClass}>Method</label>
        <input
          type="text"
          value={algo?.type || 'TPE'}
          readOnly
          className={`${inputClass} bg-dark-900 cursor-not-allowed`}
        />
        <p className="text-xs text-dark-500 mt-1">Edit in optimization settings.</p>
      </div>
      
      <div>
        <label className={labelClass}>Max Trials</label>
        <input
          type="number"
          value={spec.optimization.budget?.max_trials || 100}
          readOnly
          className={`${inputClass} bg-dark-900 cursor-not-allowed`}
        />
      </div>
    </>
  );
}

function SurrogateNodeConfig({ spec }: SpecConfigProps) {
  const surrogate = spec.optimization.surrogate;
  
  return (
    <>
      <div className="flex items-center gap-2">
        <input
          type="checkbox"
          id="surrogate-enabled"
          checked={surrogate?.enabled || false}
          readOnly
          className="w-4 h-4 rounded bg-dark-800 border-dark-600 text-primary-500 cursor-not-allowed"
        />
        <label htmlFor="surrogate-enabled" className="text-sm font-medium text-dark-300">
          Neural Surrogate {surrogate?.enabled ? 'Enabled' : 'Disabled'}
        </label>
      </div>
      
      {surrogate?.enabled && (
        <>
          <div>
            <label className={labelClass}>Model Type</label>
            <input
              type="text"
              value={surrogate.type || 'MLP'}
              readOnly
              className={`${inputClass} bg-dark-900 cursor-not-allowed`}
            />
          </div>
          
          <div>
            <label className={labelClass}>Min Training Samples</label>
            <input
              type="number"
              value={surrogate.config?.min_training_samples || 20}
              readOnly
              className={`${inputClass} bg-dark-900 cursor-not-allowed`}
            />
          </div>
        </>
      )}
      
      <p className="text-xs text-dark-500">Edit in optimization settings.</p>
    </>
  );
}

// ============================================================================
// Editable node configs
// ============================================================================

interface DesignVarNodeConfigProps {
  node: DesignVariable;
  onChange: (field: string, value: unknown) => void;
}

function DesignVarNodeConfig({ node, onChange }: DesignVarNodeConfigProps) {
  return (
    <>
      <div>
        <label className={labelClass}>Name</label>
        <input
          type="text"
          value={node.name}
          onChange={(e) => onChange('name', e.target.value)}
          className={inputClass}
        />
      </div>
      
      <div>
        <label className={labelClass}>Expression Name</label>
        <input
          type="text"
          value={node.expression_name}
          onChange={(e) => onChange('expression_name', e.target.value)}
          placeholder="NX expression name"
          className={`${inputClass} font-mono text-sm`}
        />
      </div>
      
      <div className="grid grid-cols-2 gap-2">
        <div>
          <label className={labelClass}>Min</label>
          <input
            type="number"
            value={node.bounds.min}
            onChange={(e) => onChange('bounds', { ...node.bounds, min: parseFloat(e.target.value) })}
            className={inputClass}
          />
        </div>
        <div>
          <label className={labelClass}>Max</label>
          <input
            type="number"
            value={node.bounds.max}
            onChange={(e) => onChange('bounds', { ...node.bounds, max: parseFloat(e.target.value) })}
            className={inputClass}
          />
        </div>
      </div>
      
      {node.baseline !== undefined && (
        <div>
          <label className={labelClass}>Baseline</label>
          <input
            type="number"
            value={node.baseline}
            onChange={(e) => onChange('baseline', parseFloat(e.target.value))}
            className={inputClass}
          />
        </div>
      )}
      
      <div>
        <label className={labelClass}>Units</label>
        <input
          type="text"
          value={node.units || ''}
          onChange={(e) => onChange('units', e.target.value)}
          placeholder="mm"
          className={inputClass}
        />
      </div>

      <div className="flex items-center gap-2">
        <input
          type="checkbox"
          id={`${node.id}-enabled`}
          checked={node.enabled !== false}
          onChange={(e) => onChange('enabled', e.target.checked)}
          className="w-4 h-4 rounded bg-dark-800 border-dark-600 text-primary-500 focus:ring-primary-500"
        />
        <label htmlFor={`${node.id}-enabled`} className="text-sm text-dark-300">
          Enabled
        </label>
      </div>
    </>
  );
}

interface ExtractorNodeConfigProps {
  node: Extractor;
  onChange: (field: string, value: unknown) => void;
}

function ExtractorNodeConfig({ node, onChange }: ExtractorNodeConfigProps) {
  const extractorOptions = [
    { id: 'E1', name: 'Displacement', type: 'displacement' },
    { id: 'E2', name: 'Frequency', type: 'frequency' },
    { id: 'E3', name: 'Solid Stress', type: 'solid_stress' },
    { id: 'E4', name: 'BDF Mass', type: 'mass_bdf' },
    { id: 'E5', name: 'CAD Mass', type: 'mass_expression' },
    { id: 'E8', name: 'Zernike (OP2)', type: 'zernike_op2' },
    { id: 'E9', name: 'Zernike (CSV)', type: 'zernike_csv' },
    { id: 'E10', name: 'Zernike (RMS)', type: 'zernike_rms' },
  ];

  return (
    <>
      <div>
        <label className={labelClass}>Name</label>
        <input
          type="text"
          value={node.name}
          onChange={(e) => onChange('name', e.target.value)}
          className={inputClass}
        />
      </div>
      
      <div>
        <label className={labelClass}>Extractor Type</label>
        <select
          value={node.type}
          onChange={(e) => onChange('type', e.target.value)}
          className={selectClass}
        >
          <option value="">Select...</option>
          {extractorOptions.map(opt => (
            <option key={opt.id} value={opt.type}>
              {opt.id} - {opt.name}
            </option>
          ))}
          <option value="custom">Custom Function</option>
        </select>
      </div>

      {node.type === 'custom_function' && node.function && (
        <div>
          <label className={labelClass}>Custom Function</label>
          <input
            type="text"
            value={node.function.name || ''}
            readOnly
            className={`${inputClass} bg-dark-900 cursor-not-allowed`}
          />
          <p className="text-xs text-dark-500 mt-1">Edit custom code in dedicated editor.</p>
        </div>
      )}

      <div>
        <label className={labelClass}>Outputs</label>
        <input
          type="text"
          value={node.outputs?.map(o => o.name).join(', ') || ''}
          readOnly
          placeholder="value, unit"
          className={`${inputClass} bg-dark-900 cursor-not-allowed`}
        />
        <p className="text-xs text-dark-500 mt-1">Outputs are defined by extractor type.</p>
      </div>
    </>
  );
}

interface ObjectiveNodeConfigProps {
  node: Objective;
  onChange: (field: string, value: unknown) => void;
}

function ObjectiveNodeConfig({ node, onChange }: ObjectiveNodeConfigProps) {
  return (
    <>
      <div>
        <label className={labelClass}>Name</label>
        <input
          type="text"
          value={node.name}
          onChange={(e) => onChange('name', e.target.value)}
          className={inputClass}
        />
      </div>
      
      <div>
        <label className={labelClass}>Direction</label>
        <select
          value={node.direction}
          onChange={(e) => onChange('direction', e.target.value)}
          className={selectClass}
        >
          <option value="minimize">Minimize</option>
          <option value="maximize">Maximize</option>
        </select>
      </div>
      
      <div>
        <label className={labelClass}>Weight</label>
        <input
          type="number"
          step="0.1"
          min="0"
          value={node.weight ?? 1}
          onChange={(e) => onChange('weight', parseFloat(e.target.value))}
          className={inputClass}
        />
      </div>

      {node.target !== undefined && (
        <div>
          <label className={labelClass}>Target Value</label>
          <input
            type="number"
            value={node.target}
            onChange={(e) => onChange('target', parseFloat(e.target.value))}
            className={inputClass}
          />
        </div>
      )}
    </>
  );
}

interface ConstraintNodeConfigProps {
  node: Constraint;
  onChange: (field: string, value: unknown) => void;
}

function ConstraintNodeConfig({ node, onChange }: ConstraintNodeConfigProps) {
  return (
    <>
      <div>
        <label className={labelClass}>Name</label>
        <input
          type="text"
          value={node.name}
          onChange={(e) => onChange('name', e.target.value)}
          className={inputClass}
        />
      </div>
      
      <div className="grid grid-cols-2 gap-2">
        <div>
          <label className={labelClass}>Type</label>
          <select
            value={node.type}
            onChange={(e) => onChange('type', e.target.value)}
            className={selectClass}
          >
            <option value="less_than">&lt; Less than</option>
            <option value="less_equal">&lt;= Less or equal</option>
            <option value="greater_than">&gt; Greater than</option>
            <option value="greater_equal">&gt;= Greater or equal</option>
            <option value="equal">= Equal</option>
          </select>
        </div>
        <div>
          <label className={labelClass}>Threshold</label>
          <input
            type="number"
            value={node.threshold}
            onChange={(e) => onChange('threshold', parseFloat(e.target.value))}
            className={inputClass}
          />
        </div>
      </div>

    </>
  );
}

export default NodeConfigPanelV2;
