import { useRef, useMemo } from 'react';
import { useFrame } from '@react-three/fiber';
import { Text, Billboard, QuadraticBezierLine } from '@react-three/drei';
import * as THREE from 'three';
import { useBlueprintStore } from '../../store/blueprintStore';

const NODE_COLOR = '#aaaaaa';
const ROOT_COLOR = '#ffffff';

function splitCamelCase(str: string): string[] {
  if (str === str.toUpperCase()) {
    return [str];
  }
  const result: string[] = [];
  let current = '';
  for (let i = 0; i < str.length; i++) {
    const char = str[i];
    if (char >= 'A' && char <= 'Z' && current.length > 0) {
      result.push(current);
      current = char;
    } else {
      current += char;
    }
  }
  if (current) result.push(current);
  return result;
}

function SystemNode({ 
  id, 
  name, 
  position, 
  isRoot = false,
  size = 0.8 
}: { 
  id: string;
  name: string;
  position: [number, number, number];
  isRoot?: boolean;
  size?: number;
}) {
  const meshRef = useRef<THREE.Mesh>(null);
  const { selectedNode, setSelectedNode } = useBlueprintStore();
  const isSelected = selectedNode === id;
  
  const color = isRoot ? ROOT_COLOR : NODE_COLOR;
  
  useFrame(() => {
    if (meshRef.current) {
      meshRef.current.rotation.y += 0.005;
    }
  });

  return (
    <group position={position}>
      <mesh
        ref={meshRef}
        onClick={(e) => {
          e.stopPropagation();
          setSelectedNode(id);
        }}
        onPointerOver={() => document.body.style.cursor = 'pointer'}
        onPointerOut={() => document.body.style.cursor = 'auto'}
      >
        <sphereGeometry args={[size, 32, 32]} />
        <meshStandardMaterial
          color={color}
          emissive={color}
          emissiveIntensity={isSelected ? 0.8 : 0.3}
          metalness={0.5}
          roughness={0.3}
        />
      </mesh>
      
      <Billboard follow={true}>
        {(() => {
          const parts = splitCamelCase(name);
          const lineHeight = 0.45;
          const startY = size + 0.5 + (parts.length - 1) * lineHeight / 2;
          return (
            <>
              {parts.map((part, i) => (
                <Text
                  key={i}
                  position={[0, startY - i * lineHeight, 0]}
                  fontSize={0.35}
                  color="#ffffff"
                  anchorX="center"
                  anchorY="middle"
                >
                  {part}
                </Text>
              ))}
            </>
          );
        })()}
      </Billboard>
      
      {isSelected && (
        <mesh>
          <sphereGeometry args={[size + 0.1, 32, 32]} />
          <meshBasicMaterial color={color} transparent opacity={0.3} />
        </mesh>
      )}
    </group>
  );
}

function fibonacciSpherePoint(i: number, n: number, radius: number): [number, number, number] {
  const phi = Math.acos(1 - 2 * (i + 0.5) / n);
  const theta = Math.PI * (1 + Math.sqrt(5)) * i;
  return [
    radius * Math.sin(phi) * Math.cos(theta),
    radius * Math.cos(phi),
    radius * Math.sin(phi) * Math.sin(theta),
  ];
}

function ConnectionLine({ 
  start, 
  end,
  color = '#4a5568',
  lineWidth = 1.5
}: { 
  start: [number, number, number]; 
  end: [number, number, number];
  color?: string;
  lineWidth?: number;
}) {
  const dx = end[0] - start[0];
  const dy = end[1] - start[1];
  const dz = end[2] - start[2];
  const dist = Math.sqrt(dx * dx + dy * dy + dz * dz);
  
  const midX = (start[0] + end[0]) / 2;
  const midY = (start[1] + end[1]) / 2;
  const midZ = (start[2] + end[2]) / 2;
  
  const controlOffset = dist * 0.25;
  const yDirection = dy > 0 ? 1 : -1;
  
  return (
    <QuadraticBezierLine
      start={start}
      end={end}
      mid={[
        midX - dz * controlOffset / dist,
        midY + yDirection * controlOffset,
        midZ + dx * controlOffset / dist,
      ]}
      color={color}
      lineWidth={lineWidth}
      transparent
      opacity={0.6}
    />
  );
}

export default function SystemStructure() {
  const { blueprint, selectedNode } = useBlueprintStore();
  const { subsystems, modules } = blueprint;
  
  const rootPosition: [number, number, number] = [0, 0, 0];
  
  const subsystemPositions = useMemo(() => {
    const radius = 8;
    const count = subsystems.length;
    return subsystems.map((sub, i) => {
      const position = fibonacciSpherePoint(i, count, radius);
      position[1] *= 0.6;
      return {
        id: sub.id,
        position: position as [number, number, number],
        dependCount: sub.depends_on.length,
      };
    });
  }, [subsystems]);
  
  const getSubsystemSize = (dependCount: number) => {
    const baseSize = 0.6;
    const maxAdd = 0.4;
    return baseSize + Math.min(dependCount * 0.15, maxAdd);
  };
  
  const modulePositions = useMemo(() => {
    const positions: { id: string; name: string; position: [number, number, number]; parentId: string }[] = [];
    const moduleRadius = 2.5;
    
    subsystems.forEach((sub) => {
      const subModules = modules.filter(m => m.parent_subsystem === sub.id);
      const subPos = subsystemPositions.find(p => p.id === sub.id);
      if (!subPos) return;
      
      const count = subModules.length || 1;
      
      subModules.forEach((mod, i) => {
        const offset = fibonacciSpherePoint(i, count, moduleRadius);
        const parentY = subPos.position[1];
        const yOffset = parentY > 0 ? 1.2 : -1.2;
        positions.push({
          id: mod.id,
          name: mod.name,
          position: [
            subPos.position[0] + offset[0],
            parentY + yOffset + offset[1] * 0.5,
            subPos.position[2] + offset[2],
          ] as [number, number, number],
          parentId: sub.id,
        });
      });
    });
    
    return positions;
  }, [subsystems, modules, subsystemPositions]);
  
  const dependencies = useMemo(() => {
    const lines: { from: [number, number, number]; to: [number, number, number]; fromId: string; toId: string }[] = [];
    
    subsystems.forEach(sub => {
      const fromPos = subsystemPositions.find(p => p.id === sub.id);
      if (!fromPos) return;
      
      sub.depends_on.forEach(depId => {
        const toPos = subsystemPositions.find(p => p.id === depId);
        if (toPos) {
          lines.push({
            from: fromPos.position,
            to: toPos.position,
            fromId: sub.id,
            toId: depId,
          });
        }
      });
    });
    
    return lines;
  }, [subsystems, subsystemPositions]);

  return (
    <group>
      <SystemNode
        id="root"
        name={blueprint.meta.name}
        position={rootPosition}
        isRoot
        size={1.2}
      />
      
      {subsystemPositions.map((sub) => (
        <SystemNode
          key={sub.id}
          id={sub.id}
          name={sub.id}
          position={sub.position}
          size={getSubsystemSize(sub.dependCount)}
        />
      ))}
      
      {modulePositions.map((mod) => (
        <SystemNode
          key={mod.id}
          id={mod.id}
          name={mod.name}
          position={mod.position}
          size={0.4}
        />
      ))}
      
      {dependencies.map((dep, i) => {
        const isHighlighted = selectedNode && (dep.fromId === selectedNode || dep.toId === selectedNode);
        return (
          <ConnectionLine 
            key={i} 
            start={dep.from} 
            end={dep.to} 
            color={isHighlighted ? '#ffffff' : '#666666'} 
            lineWidth={isHighlighted ? 3 : 1.5}
          />
        );
      })}
      
      {subsystemPositions.map((sub) => {
        const isHighlighted = selectedNode === sub.id || selectedNode === 'root';
        return (
          <ConnectionLine 
            key={`root-${sub.id}`} 
            start={rootPosition} 
            end={sub.position} 
            color={isHighlighted ? '#ffffff' : '#666666'}
            lineWidth={isHighlighted ? 3 : 1.5}
          />
        );
      })}
      
      {modulePositions.map((mod) => {
        const parent = subsystemPositions.find(p => p.id === mod.parentId);
        if (!parent) return null;
        const isHighlighted = selectedNode === mod.id || selectedNode === mod.parentId;
        return (
          <ConnectionLine 
            key={`mod-${mod.id}`} 
            start={parent.position} 
            end={mod.position} 
            color={isHighlighted ? '#ffffff' : '#666666'}
            lineWidth={isHighlighted ? 3 : 1.5}
          />
        );
      })}
    </group>
  );
}
