/**
 * Parallel Coordinates Plot - Protocol 13
 * High-dimensional visualization for multi-objective Pareto fronts
 * Shows objectives and design variables as parallel axes
 */

import { useState } from 'react';

interface ParetoTrial {
  trial_number: number;
  values: number[];
  params: Record<string, number>;
  constraint_satisfied?: boolean;
}

interface Objective {
  name: string;
  type: 'minimize' | 'maximize';
  unit?: string;
}

interface DesignVariable {
  name: string;
  unit?: string;
  min: number;
  max: number;
}

interface ParallelCoordinatesPlotProps {
  paretoData: ParetoTrial[];
  objectives: Objective[];
  designVariables: DesignVariable[];
}

export function ParallelCoordinatesPlot({
  paretoData,
  objectives,
  designVariables
}: ParallelCoordinatesPlotProps) {
  const [hoveredTrial, setHoveredTrial] = useState<number | null>(null);
  const [selectedTrials, setSelectedTrials] = useState<Set<number>>(new Set());

  if (paretoData.length === 0) {
    return (
      <div className="bg-dark-700 rounded-lg p-6 border border-dark-600">
        <h3 className="text-lg font-semibold mb-4 text-dark-100">Parallel Coordinates</h3>
        <div className="h-96 flex items-center justify-center text-dark-300">
          No Pareto front data yet
        </div>
      </div>
    );
  }

  // Combine objectives and design variables into axes
  const axes: Array<{name: string, label: string, type: 'objective' | 'param'}> = [
    ...objectives.map((obj, i) => ({
      name: `obj_${i}`,
      label: obj.unit ? `${obj.name} (${obj.unit})` : obj.name,
      type: 'objective' as const
    })),
    ...designVariables.map(dv => ({
      name: dv.name,
      label: dv.unit ? `${dv.name} (${dv.unit})` : dv.name,
      type: 'param' as const
    }))
  ];

  // Normalize data to [0, 1] for each axis
  const normalizedData = paretoData.map(trial => {
    const allValues: number[] = [];

    // Add objectives
    trial.values.forEach(val => allValues.push(val));

    // Add design variables
    designVariables.forEach(dv => {
      allValues.push(trial.params[dv.name]);
    });

    return {
      trial_number: trial.trial_number,
      values: allValues,
      feasible: trial.constraint_satisfied !== false
    };
  });

  // Calculate min/max for each axis
  const ranges = axes.map((_, axisIdx) => {
    const values = normalizedData.map(d => d.values[axisIdx]);
    return {
      min: Math.min(...values),
      max: Math.max(...values)
    };
  });

  // Normalize function
  const normalize = (value: number, axisIdx: number): number => {
    const range = ranges[axisIdx];
    if (range.max === range.min) return 0.5;
    return (value - range.min) / (range.max - range.min);
  };

  // Chart dimensions
  const width = 800;
  const height = 400;
  const margin = { top: 80, right: 20, bottom: 40, left: 20 };
  const plotWidth = width - margin.left - margin.right;
  const plotHeight = height - margin.top - margin.bottom;

  const axisSpacing = plotWidth / (axes.length - 1);

  // Toggle trial selection
  const toggleTrial = (trialNum: number) => {
    const newSelected = new Set(selectedTrials);
    if (newSelected.has(trialNum)) {
      newSelected.delete(trialNum);
    } else {
      newSelected.add(trialNum);
    }
    setSelectedTrials(newSelected);
  };

  return (
    <div className="bg-dark-700 rounded-lg p-6 border border-dark-600">
      <div className="flex items-center justify-between mb-4">
        <h3 className="text-lg font-semibold text-dark-100">
          Parallel Coordinates ({paretoData.length} solutions)
        </h3>
        {selectedTrials.size > 0 && (
          <button
            onClick={() => setSelectedTrials(new Set())}
            className="text-xs px-3 py-1 bg-dark-600 hover:bg-dark-500 rounded text-dark-200"
          >
            Clear Selection ({selectedTrials.size})
          </button>
        )}
      </div>

      <svg width={width} height={height} className="overflow-visible">
        <g transform={`translate(${margin.left}, ${margin.top})`}>
          {/* Draw axes */}
          {axes.map((axis, i) => {
            const x = i * axisSpacing;
            return (
              <g key={axis.name} transform={`translate(${x}, 0)`}>
                {/* Axis line */}
                <line
                  y1={0}
                  y2={plotHeight}
                  stroke="#475569"
                  strokeWidth={2}
                />

                {/* Axis label */}
                <text
                  y={-10}
                  textAnchor="middle"
                  fill="#94a3b8"
                  fontSize={12}
                  className="select-none"
                  transform={`rotate(-45, 0, -10)`}
                >
                  {axis.label}
                </text>

                {/* Min/max labels */}
                <text
                  y={plotHeight + 15}
                  textAnchor="middle"
                  fill="#64748b"
                  fontSize={10}
                >
                  {ranges[i].min.toFixed(2)}
                </text>
                <text
                  y={-25}
                  textAnchor="middle"
                  fill="#64748b"
                  fontSize={10}
                >
                  {ranges[i].max.toFixed(2)}
                </text>
              </g>
            );
          })}

          {/* Draw lines for each trial */}
          {normalizedData.map(trial => {
            const isHovered = hoveredTrial === trial.trial_number;
            const isSelected = selectedTrials.has(trial.trial_number);
            const isHighlighted = isHovered || isSelected;

            // Build path
            const pathData = axes.map((_, i) => {
              const x = i * axisSpacing;
              const normalizedY = normalize(trial.values[i], i);
              const y = plotHeight * (1 - normalizedY);
              return i === 0 ? `M ${x} ${y}` : `L ${x} ${y}`;
            }).join(' ');

            return (
              <path
                key={trial.trial_number}
                d={pathData}
                fill="none"
                stroke={
                  isSelected ? '#fbbf24' :
                  trial.feasible ? '#10b981' : '#ef4444'
                }
                strokeWidth={isHighlighted ? 2.5 : 1}
                opacity={
                  selectedTrials.size > 0
                    ? (isSelected ? 1 : 0.1)
                    : (isHighlighted ? 1 : 0.4)
                }
                strokeLinecap="round"
                strokeLinejoin="round"
                className="transition-all duration-200 cursor-pointer"
                onMouseEnter={() => setHoveredTrial(trial.trial_number)}
                onMouseLeave={() => setHoveredTrial(null)}
                onClick={() => toggleTrial(trial.trial_number)}
              />
            );
          })}

          {/* Hover tooltip */}
          {hoveredTrial !== null && (
            <g transform={`translate(${plotWidth + 10}, 20)`}>
              <rect
                x={0}
                y={0}
                width={120}
                height={60}
                fill="#1e293b"
                stroke="#334155"
                strokeWidth={1}
                rx={4}
              />
              <text x={10} y={20} fill="#e2e8f0" fontSize={12} fontWeight="bold">
                Trial #{hoveredTrial}
              </text>
              <text x={10} y={38} fill="#94a3b8" fontSize={10}>
                Click to select
              </text>
              <text x={10} y={52} fill="#94a3b8" fontSize={10}>
                {selectedTrials.has(hoveredTrial) ? '✓ Selected' : '○ Not selected'}
              </text>
            </g>
          )}
        </g>
      </svg>

      {/* Legend */}
      <div className="flex gap-6 justify-center mt-4 text-sm">
        <div className="flex items-center gap-2">
          <div className="w-8 h-0.5 bg-green-400" />
          <span className="text-dark-200">Feasible</span>
        </div>
        <div className="flex items-center gap-2">
          <div className="w-8 h-0.5 bg-red-400" />
          <span className="text-dark-200">Infeasible</span>
        </div>
        <div className="flex items-center gap-2">
          <div className="w-8 h-0.5 bg-yellow-400" style={{ height: '2px' }} />
          <span className="text-dark-200">Selected</span>
        </div>
      </div>
    </div>
  );
}
