/**
 * ParameterServer.jsx — SaltyBot Centralized Dynamic Parameter Configuration (Issue #471)
 *
 * Features:
 * - Load and display parameters grouped by category (hardware/perception/controls/social/safety/debug)
 * - Edit parameters with real-time validation (type checking, min/max ranges)
 * - Display metadata: type, range, description, is_safety flag
 * - Load named presets (indoor/outdoor/demo/debug)
 * - Safety confirmation for critical parameters
 * - Persist parameter overrides
 * - Visual feedback for modified parameters
 * - Reset to defaults option
 */

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

const PARAM_GROUPS = ['hardware', 'perception', 'controls', 'social', 'safety', 'debug'];
const GROUP_COLORS = {
  hardware: 'border-blue-500',
  perception: 'border-purple-500',
  controls: 'border-green-500',
  social: 'border-rose-500',
  safety: 'border-red-500',
  debug: 'border-yellow-500',
};
const GROUP_BG = {
  hardware: 'bg-blue-950',
  perception: 'bg-purple-950',
  controls: 'bg-green-950',
  social: 'bg-rose-950',
  safety: 'bg-red-950',
  debug: 'bg-yellow-950',
};

export function ParameterServer({ subscribe, callService }) {
  const [params, setParams] = useState({});
  const [editValues, setEditValues] = useState({});
  const [presets, setPresets] = useState(['indoor', 'outdoor', 'demo', 'debug']);
  const [activeGroup, setActiveGroup] = useState('hardware');
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);
  const [expandedParams, setExpandedParams] = useState(new Set());
  const [pendingChanges, setPendingChanges] = useState(new Set());
  const [confirmDialog, setConfirmDialog] = useState(null);

  // Fetch parameters from server
  useEffect(() => {
    const fetchParams = async () => {
      try {
        setLoading(true);
        // Try to call the service or subscribe to parameter topic
        if (subscribe) {
          // Subscribe to parameter updates (if available)
          subscribe('/saltybot/parameters', 'std_msgs/String', (msg) => {
            try {
              const paramsData = JSON.parse(msg.data);
              setParams(paramsData);
              setError(null);
            } catch (e) {
              console.error('Failed to parse parameters:', e);
            }
          });
        }
        setLoading(false);
      } catch (err) {
        setError(`Failed to fetch parameters: ${err.message}`);
        setLoading(false);
      }
    };

    fetchParams();
  }, [subscribe]);

  const toggleParamExpanded = useCallback((paramName) => {
    setExpandedParams(prev => {
      const next = new Set(prev);
      next.has(paramName) ? next.delete(paramName) : next.add(paramName);
      return next;
    });
  }, []);

  const handleParamChange = useCallback((paramName, value, paramInfo) => {
    // Validate input based on type
    let validatedValue = value;
    let isValid = true;

    if (paramInfo.type === 'int') {
      validatedValue = parseInt(value, 10);
      isValid = !isNaN(validatedValue);
    } else if (paramInfo.type === 'float') {
      validatedValue = parseFloat(value);
      isValid = !isNaN(validatedValue);
    } else if (paramInfo.type === 'bool') {
      validatedValue = value === 'true' || value === true || value === 1;
    }

    // Check range
    if (isValid && paramInfo.min !== undefined && validatedValue < paramInfo.min) {
      isValid = false;
    }
    if (isValid && paramInfo.max !== undefined && validatedValue > paramInfo.max) {
      isValid = false;
    }

    if (isValid) {
      setEditValues(prev => ({
        ...prev,
        [paramName]: validatedValue
      }));

      if (paramInfo.value !== validatedValue) {
        setPendingChanges(prev => new Set([...prev, paramName]));
      } else {
        setPendingChanges(prev => {
          const next = new Set(prev);
          next.delete(paramName);
          return next;
        });
      }

      // For safety parameters, show confirmation
      if (paramInfo.is_safety && paramInfo.value !== validatedValue) {
        setConfirmDialog({
          paramName,
          paramInfo,
          newValue: validatedValue,
          message: `Safety parameter "${paramName}" will be changed. This may affect robot behavior.`
        });
      }
    }
  }, []);

  const confirmParameterChange = useCallback(() => {
    if (!confirmDialog) return;

    const { paramName, newValue } = confirmDialog;
    // Persist to backend
    if (callService) {
      callService('/saltybot/set_param', {
        name: paramName,
        value: newValue
      });
    }

    setConfirmDialog(null);
  }, [confirmDialog, callService]);

  const rejectParameterChange = useCallback(() => {
    if (!confirmDialog) {
      setConfirmDialog(null);
      return;
    }

    const { paramName } = confirmDialog;
    setEditValues(prev => {
      const next = { ...prev };
      delete next[paramName];
      return next;
    });

    setPendingChanges(prev => {
      const next = new Set(prev);
      next.delete(paramName);
      return next;
    });

    setConfirmDialog(null);
  }, [confirmDialog]);

  const loadPreset = useCallback((presetName) => {
    if (callService) {
      callService('/saltybot/load_preset', {
        preset: presetName
      });
    }
  }, [callService]);

  const saveOverrides = useCallback(() => {
    if (callService) {
      callService('/saltybot/save_overrides', {});
    }
    setPendingChanges(new Set());
  }, [callService]);

  const resetParameter = useCallback((paramName) => {
    setEditValues(prev => {
      const next = { ...prev };
      delete next[paramName];
      return next;
    });
    setPendingChanges(prev => {
      const next = new Set(prev);
      next.delete(paramName);
      return next;
    });
  }, []);

  const resetAllParameters = useCallback(() => {
    setEditValues({});
    setPendingChanges(new Set());
  }, []);

  if (loading) {
    return (
      <div className="flex items-center justify-center h-screen">
        <div className="text-cyan-400">Loading parameters...</div>
      </div>
    );
  }

  const groupParams = params[activeGroup] || {};

  return (
    <div className="flex flex-col h-full gap-4 p-4 bg-[#050510]">
      {/* Header */}
      <div className="flex items-center justify-between gap-4">
        <div>
          <h1 className="text-xl font-bold text-cyan-400">⚙️ Parameter Server</h1>
          <p className="text-xs text-gray-500">Dynamic reconfiguration • {Object.keys(groupParams).length} parameters</p>
        </div>
        <div className="flex gap-2">
          <button
            onClick={saveOverrides}
            disabled={pendingChanges.size === 0}
            className="px-3 py-1 text-xs rounded border border-green-700 bg-green-950 text-green-400 hover:bg-green-900 disabled:opacity-50 disabled:cursor-not-allowed"
          >
            💾 Save ({pendingChanges.size})
          </button>
          <button
            onClick={resetAllParameters}
            disabled={pendingChanges.size === 0}
            className="px-3 py-1 text-xs rounded border border-gray-700 bg-gray-950 text-gray-400 hover:bg-gray-900 disabled:opacity-50 disabled:cursor-not-allowed"
          >
            Reset All
          </button>
        </div>
      </div>

      {/* Presets */}
      <div className="flex gap-2 pb-2 border-b border-gray-800">
        <span className="text-xs text-gray-500 py-1">Presets:</span>
        {presets.map(preset => (
          <button
            key={preset}
            onClick={() => loadPreset(preset)}
            className="px-2 py-1 text-xs rounded border border-cyan-700 bg-cyan-950 text-cyan-400 hover:bg-cyan-900 transition-colors"
          >
            {preset.charAt(0).toUpperCase() + preset.slice(1)}
          </button>
        ))}
      </div>

      {/* Group Tabs */}
      <div className="flex gap-1 flex-wrap">
        {PARAM_GROUPS.map(group => (
          <button
            key={group}
            onClick={() => setActiveGroup(group)}
            className={`px-3 py-1 text-xs font-bold rounded transition-colors ${
              activeGroup === group
                ? `border-2 ${GROUP_COLORS[group]} ${GROUP_BG[group]} text-white`
                : 'border border-gray-700 bg-gray-950 text-gray-400 hover:bg-gray-900'
            }`}
          >
            {group.charAt(0).toUpperCase() + group.slice(1)}
          </button>
        ))}
      </div>

      {/* Error Display */}
      {error && (
        <div className="p-3 rounded bg-red-950 border border-red-700 text-red-400 text-sm">
          ⚠️ {error}
        </div>
      )}

      {/* Parameters */}
      <div className="flex-1 overflow-y-auto space-y-2">
        {Object.entries(groupParams).map(([paramName, paramInfo]) => {
          const isModified = pendingChanges.has(paramName);
          const currentValue = editValues[paramName] !== undefined ? editValues[paramName] : paramInfo.value;
          const isExpanded = expandedParams.has(paramName);

          return (
            <div
              key={paramName}
              className={`p-3 rounded border transition-all ${
                paramInfo.is_safety
                  ? 'border-red-700 bg-red-950 bg-opacity-30'
                  : 'border-gray-700 bg-gray-950 bg-opacity-30 hover:bg-opacity-50'
              } ${isModified ? 'ring-2 ring-yellow-500' : ''}`}
            >
              <div className="flex items-start justify-between gap-2">
                <div className="flex-1 min-w-0">
                  <div className="flex items-center gap-2">
                    <button
                      onClick={() => toggleParamExpanded(paramName)}
                      className="text-gray-500 hover:text-gray-300 px-1"
                    >
                      {isExpanded ? '▼' : '▶'}
                    </button>
                    <div className="flex-1">
                      <div className="font-mono text-sm text-gray-300 break-all">
                        {paramName}
                        {paramInfo.is_safety && <span className="ml-2 text-xs text-red-400">🔒 SAFETY</span>}
                        {isModified && <span className="ml-2 text-xs text-yellow-400">⚡ Modified</span>}
                      </div>
                      <div className="text-xs text-gray-500 mt-0.5">{paramInfo.description}</div>
                    </div>
                  </div>
                </div>
                {isModified && (
                  <button
                    onClick={() => resetParameter(paramName)}
                    className="px-2 py-0.5 text-xs rounded border border-gray-600 bg-gray-900 text-gray-400 hover:bg-gray-800"
                  >
                    Reset
                  </button>
                )}
              </div>

              {isExpanded && (
                <div className="mt-3 ml-6 space-y-2">
                  {/* Type and Range Info */}
                  <div className="text-xs text-gray-500 grid grid-cols-3 gap-2">
                    <div>Type: <span className="text-cyan-400">{paramInfo.type}</span></div>
                    {paramInfo.min !== undefined && (
                      <div>Min: <span className="text-cyan-400">{paramInfo.min}</span></div>
                    )}
                    {paramInfo.max !== undefined && (
                      <div>Max: <span className="text-cyan-400">{paramInfo.max}</span></div>
                    )}
                  </div>

                  {/* Input Field */}
                  <div className="flex items-center gap-2">
                    {paramInfo.type === 'bool' ? (
                      <select
                        value={currentValue ? 'true' : 'false'}
                        onChange={(e) => handleParamChange(paramName, e.target.value === 'true', paramInfo)}
                        className="flex-1 px-2 py-1 rounded bg-gray-900 border border-gray-700 text-gray-300 text-sm focus:outline-none focus:border-cyan-500"
                      >
                        <option value="true">True</option>
                        <option value="false">False</option>
                      </select>
                    ) : (
                      <input
                        type={paramInfo.type === 'int' ? 'number' : 'text'}
                        value={currentValue}
                        onChange={(e) => handleParamChange(paramName, e.target.value, paramInfo)}
                        step={paramInfo.type === 'float' ? '0.01' : '1'}
                        className="flex-1 px-2 py-1 rounded bg-gray-900 border border-gray-700 text-gray-300 text-sm focus:outline-none focus:border-cyan-500"
                      />
                    )}
                    <span className="text-xs text-gray-500">
                      {isModified ? (
                        <>
                          <span className="text-gray-600">{paramInfo.value}</span>
                          <span className="mx-1">→</span>
                          <span className="text-yellow-400">{currentValue}</span>
                        </>
                      ) : (
                        <span className="text-gray-400">{currentValue}</span>
                      )}
                    </span>
                  </div>

                  {/* Range Visualization */}
                  {paramInfo.type !== 'bool' && paramInfo.type !== 'string' && paramInfo.min !== undefined && paramInfo.max !== undefined && (
                    <div className="w-full bg-gray-900 rounded h-1 overflow-hidden">
                      <div
                        className="h-full bg-cyan-600"
                        style={{
                          width: `${((currentValue - paramInfo.min) / (paramInfo.max - paramInfo.min)) * 100}%`
                        }}
                      />
                    </div>
                  )}
                </div>
              )}
            </div>
          );
        })}
      </div>

      {/* Safety Confirmation Dialog */}
      {confirmDialog && (
        <div className="fixed inset-0 bg-black bg-opacity-70 flex items-center justify-center z-50">
          <div className="bg-gray-900 border-2 border-red-600 rounded p-4 max-w-md">
            <h3 className="text-lg font-bold text-red-400 mb-2">⚠️ Safety Parameter Confirmation</h3>
            <p className="text-gray-300 mb-4">{confirmDialog.message}</p>
            <div className="bg-gray-950 p-2 rounded mb-4 text-sm font-mono">
              <div className="text-gray-500">{confirmDialog.paramName}</div>
              <div className="text-gray-400">{confirmDialog.paramInfo.value} → <span className="text-yellow-400">{confirmDialog.newValue}</span></div>
            </div>
            <div className="flex gap-2">
              <button
                onClick={confirmParameterChange}
                className="flex-1 px-3 py-2 rounded bg-red-950 border border-red-700 text-red-400 hover:bg-red-900 font-bold"
              >
                ✓ Confirm
              </button>
              <button
                onClick={rejectParameterChange}
                className="flex-1 px-3 py-2 rounded bg-gray-950 border border-gray-700 text-gray-400 hover:bg-gray-900"
              >
                ✕ Cancel
              </button>
            </div>
          </div>
        </div>
      )}
    </div>
  );
}
