import { useState, useCallback, DragEvent } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
import { Card } from '../../ui/Card';
import { Button } from '../../ui/Button';
import {
  CheckCircle,
  XCircle,
  RefreshCcw,
  Link2,
  GripVertical,
  Trophy,
  Star,
  Target,
  Zap
} from 'lucide-react';

export interface MatchingItem {
  id: string;
  content: string;
}

export interface MatchingPair {
  leftId: string;
  rightId: string;
}

export interface MatchingExerciseProps {
  leftItems: MatchingItem[];
  rightItems: MatchingItem[];
  correctPairs: MatchingPair[];
  onComplete?: (result: MatchingResult) => void;
  title?: string;
  description?: string;
  maxPoints?: number;
  shuffleItems?: boolean;
}

export interface MatchingResult {
  correct: number;
  total: number;
  attempts: number;
  score: number;
  maxScore: number;
  isPerfect: boolean;
  pairs: MatchedPairResult[];
}

interface MatchedPairResult {
  leftId: string;
  rightId: string;
  isCorrect: boolean;
}

interface Match {
  leftId: string;
  rightId: string;
  isCorrect?: boolean;
  checked?: boolean;
}

// Fisher-Yates shuffle algorithm
function shuffleArray<T>(array: T[]): T[] {
  const shuffled = [...array];
  for (let i = shuffled.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    [shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
  }
  return shuffled;
}

export function MatchingExercise({
  leftItems,
  rightItems,
  correctPairs,
  onComplete,
  title = 'Emparejamiento',
  description = 'Relaciona los elementos de la columna izquierda con los de la derecha',
  maxPoints = 100,
  shuffleItems = true,
}: MatchingExerciseProps) {
  // Initialize items with optional shuffle
  const [displayLeftItems, setDisplayLeftItems] = useState<MatchingItem[]>(() =>
    shuffleItems ? shuffleArray(leftItems) : leftItems
  );
  const [displayRightItems, setDisplayRightItems] = useState<MatchingItem[]>(() =>
    shuffleItems ? shuffleArray(rightItems) : rightItems
  );

  const [matches, setMatches] = useState<Match[]>([]);
  const [selectedLeft, setSelectedLeft] = useState<string | null>(null);
  const [selectedRight, setSelectedRight] = useState<string | null>(null);
  const [attempts, setAttempts] = useState(0);
  const [showResults, setShowResults] = useState(false);
  const [dragOverLeft, setDragOverLeft] = useState<string | null>(null);
  const [dragOverRight, setDragOverRight] = useState<string | null>(null);

  // Check if all pairs are matched
  const allMatched = matches.length === leftItems.length;

  // Calculate score based on attempts
  const calculateScore = useCallback((correctCount: number, totalAttempts: number): number => {
    if (correctCount === 0) return 0;

    // Base score per correct match
    const baseScore = maxPoints / leftItems.length;

    // Penalty for attempts (starts at 100%, decreases with each attempt)
    const efficiency = Math.max(0.5, 1 - (totalAttempts - leftItems.length) * 0.05);

    return Math.round(correctCount * baseScore * efficiency);
  }, [maxPoints, leftItems.length]);

  // Handle left item click
  const handleLeftClick = (itemId: string) => {
    if (showResults) return;

    if (selectedLeft === itemId) {
      setSelectedLeft(null);
    } else {
      setSelectedLeft(itemId);
      // If right is already selected, create match
      if (selectedRight) {
        handleCreateMatch(itemId, selectedRight);
      }
    }
  };

  // Handle right item click
  const handleRightClick = (itemId: string) => {
    if (showResults) return;

    if (selectedRight === itemId) {
      setSelectedRight(null);
    } else {
      setSelectedRight(itemId);
      // If left is already selected, create match
      if (selectedLeft) {
        handleCreateMatch(selectedLeft, itemId);
      }
    }
  };

  // Create a new match
  const handleCreateMatch = (leftId: string, rightId: string) => {
    // Check if either item is already matched
    const isLeftMatched = matches.some(m => m.leftId === leftId);
    const isRightMatched = matches.some(m => m.rightId === rightId);

    if (isLeftMatched || isRightMatched) return;

    setMatches(prev => [...prev, { leftId, rightId }]);
    setSelectedLeft(null);
    setSelectedRight(null);
    setAttempts(prev => prev + 1);
  };

  // Handle drag start
  const handleDragStart = (e: DragEvent<HTMLDivElement>, itemId: string, side: 'left' | 'right') => {
    e.dataTransfer.setData('text/plain', JSON.stringify({ itemId, side }));
    e.dataTransfer.effectAllowed = 'link';
  };

  // Handle drag over
  const handleDragOver = (e: DragEvent<HTMLDivElement>, itemId: string, side: 'left' | 'right') => {
    e.preventDefault();
    e.dataTransfer.dropEffect = 'link';
    if (side === 'left') {
      setDragOverLeft(itemId);
    } else {
      setDragOverRight(itemId);
    }
  };

  // Handle drag leave
  const handleDragLeave = (side: 'left' | 'right') => {
    if (side === 'left') {
      setDragOverLeft(null);
    } else {
      setDragOverRight(null);
    }
  };

  // Handle drop
  const handleDrop = (e: DragEvent<HTMLDivElement>, targetId: string, targetSide: 'left' | 'right') => {
    e.preventDefault();

    try {
      const data = JSON.parse(e.dataTransfer.getData('text/plain'));
      const { itemId: draggedId, side: draggedSide } = data;

      // Prevent dropping on same side
      if (draggedSide === targetSide) return;

      // Create match
      if (draggedSide === 'left' && targetSide === 'right') {
        handleCreateMatch(draggedId, targetId);
      } else if (draggedSide === 'right' && targetSide === 'left') {
        handleCreateMatch(targetId, draggedId);
      }
    } catch {
      // Invalid drag data
    }

    setDragOverLeft(null);
    setDragOverRight(null);
  };

  // Remove a match
  const handleRemoveMatch = (leftId: string) => {
    if (showResults) return;
    setMatches(prev => prev.filter(m => m.leftId !== leftId));
  };

  // Validate all matches
  const handleValidate = () => {
    const validatedMatches = matches.map(match => {
      const isCorrect = correctPairs.some(
        p => p.leftId === match.leftId && p.rightId === match.rightId
      );
      return { ...match, isCorrect, checked: true };
    });

    setMatches(validatedMatches);
    setShowResults(true);

    const correctCount = validatedMatches.filter(m => m.isCorrect).length;
    const score = calculateScore(correctCount, attempts);

    const result: MatchingResult = {
      correct: correctCount,
      total: leftItems.length,
      attempts,
      score,
      maxScore: maxPoints,
      isPerfect: correctCount === leftItems.length,
      pairs: validatedMatches.map(m => ({
        leftId: m.leftId,
        rightId: m.rightId,
        isCorrect: m.isCorrect || false,
      })),
    };

    if (onComplete) {
      onComplete(result);
    }
  };

  // Reset exercise
  const handleReset = () => {
    setDisplayLeftItems(shuffleItems ? shuffleArray(leftItems) : leftItems);
    setDisplayRightItems(shuffleItems ? shuffleArray(rightItems) : rightItems);
    setMatches([]);
    setSelectedLeft(null);
    setSelectedRight(null);
    setAttempts(0);
    setShowResults(false);
    setDragOverLeft(null);
    setDragOverRight(null);
  };

  // Get matched item for display
  const getMatchedRightItem = (leftId: string) => {
    const match = matches.find(m => m.leftId === leftId);
    if (!match) return null;
    return rightItems.find(item => item.id === match.rightId);
  };

  const getMatchedLeftItem = (rightId: string) => {
    const match = matches.find(m => m.rightId === rightId);
    if (!match) return null;
    return leftItems.find(item => item.id === match.leftId);
  };

  // Check if item is matched
  const isLeftMatched = (id: string) => matches.some(m => m.leftId === id);
  const isRightMatched = (id: string) => matches.some(m => m.rightId === id);

  // Get match status
  const getMatchStatus = (leftId: string): 'correct' | 'incorrect' | 'unchecked' | null => {
    const match = matches.find(m => m.leftId === leftId);
    if (!match || !showResults) return null;
    return match.isCorrect ? 'correct' : 'incorrect';
  };

  // Calculate results
  const correctCount = matches.filter(m => m.isCorrect).length;
  const score = calculateScore(correctCount, attempts);

  return (
    <div className="space-y-6">
      {/* Header */}
      <div className="flex items-start justify-between">
        <div>
          <h3 className="text-xl font-bold text-gray-900">{title}</h3>
          <p className="text-gray-600 mt-1">{description}</p>
        </div>
        <div className="flex items-center gap-3">
          <div className="flex items-center gap-2 text-amber-600 bg-amber-50 px-3 py-1.5 rounded-full">
            <Target size={16} />
            <span className="font-semibold text-sm">{maxPoints} pts</span>
          </div>
          <div className="flex items-center gap-2 text-blue-600 bg-blue-50 px-3 py-1.5 rounded-full">
            <Zap size={16} />
            <span className="font-semibold text-sm">{attempts} {attempts === 1 ? 'intento' : 'intentos'}</span>
          </div>
        </div>
      </div>

      {/* Matching Area */}
      <Card className="p-6">
        <div className="grid grid-cols-1 md:grid-cols-2 gap-8">
          {/* Left Column */}
          <div className="space-y-3">
            <h4 className="text-sm font-semibold text-gray-500 uppercase tracking-wider mb-4">
              Columna A
            </h4>
            {displayLeftItems.map(item => {
              const matchedItem = getMatchedRightItem(item.id);
              const status = getMatchStatus(item.id);
              const isSelected = selectedLeft === item.id;
              const isMatched = isLeftMatched(item.id);

              return (
                <motion.div
                  key={item.id}
                  draggable={!showResults && !isMatched}
                  onDragStart={(e) => handleDragStart(e as unknown as DragEvent<HTMLDivElement>, item.id, 'left')}
                  onDragOver={(e) => !showResults && handleDragOver(e as unknown as DragEvent<HTMLDivElement>, item.id, 'left')}
                  onDragLeave={() => handleDragLeave('left')}
                  onDrop={(e) => handleDrop(e as unknown as DragEvent<HTMLDivElement>, item.id, 'left')}
                  onClick={() => handleLeftClick(item.id)}
                  whileHover={!showResults && !isMatched ? { scale: 1.02 } : {}}
                  whileTap={!showResults && !isMatched ? { scale: 0.98 } : {}}
                  className={`
                    relative p-4 rounded-lg border-2 transition-all cursor-pointer
                    ${!showResults && !isMatched ? 'hover:border-blue-300 hover:shadow-md' : ''}
                    ${isSelected ? 'border-blue-500 bg-blue-50' : ''}
                    ${isMatched && !showResults ? 'border-green-300 bg-green-50' : ''}
                    ${status === 'correct' ? 'border-green-500 bg-green-50' : ''}
                    ${status === 'incorrect' ? 'border-red-500 bg-red-50' : ''}
                    ${dragOverLeft === item.id ? 'border-blue-400 bg-blue-100' : ''}
                    ${!isMatched && !isSelected ? 'border-gray-200' : ''}
                  `}
                >
                  <div className="flex items-center gap-3">
                    <GripVertical size={16} className="text-gray-400 flex-shrink-0" />
                    <span className="font-medium text-gray-800">{item.content}</span>
                  </div>

                  {/* Match indicator */}
                  {matchedItem && (
                    <div className="mt-3 pt-3 border-t border-gray-200">
                      <div className="flex items-center gap-2 text-sm">
                        <Link2 size={14} className="text-gray-400" />
                        <span className="text-gray-600">{matchedItem.content}</span>
                      </div>
                    </div>
                  )}

                  {/* Status icons */}
                  {showResults && status && (
                    <div className="absolute top-2 right-2">
                      {status === 'correct' ? (
                        <CheckCircle size={20} className="text-green-600" />
                      ) : (
                        <XCircle size={20} className="text-red-600" />
                      )}
                    </div>
                  )}

                  {/* Remove button */}
                  {isMatched && !showResults && (
                    <button
                      onClick={(e) => {
                        e.stopPropagation();
                        handleRemoveMatch(item.id);
                      }}
                      className="absolute top-2 right-2 p-1 hover:bg-gray-200 rounded-full transition-colors"
                    >
                      <XCircle size={16} className="text-gray-400 hover:text-red-500" />
                    </button>
                  )}
                </motion.div>
              );
            })}
          </div>

          {/* Right Column */}
          <div className="space-y-3">
            <h4 className="text-sm font-semibold text-gray-500 uppercase tracking-wider mb-4">
              Columna B
            </h4>
            {displayRightItems.map(item => {
              const matchedItem = getMatchedLeftItem(item.id);
              const isSelected = selectedRight === item.id;
              const isMatched = isRightMatched(item.id);

              return (
                <motion.div
                  key={item.id}
                  draggable={!showResults && !isMatched}
                  onDragStart={(e) => handleDragStart(e as unknown as DragEvent<HTMLDivElement>, item.id, 'right')}
                  onDragOver={(e) => !showResults && handleDragOver(e as unknown as DragEvent<HTMLDivElement>, item.id, 'right')}
                  onDragLeave={() => handleDragLeave('right')}
                  onDrop={(e) => handleDrop(e as unknown as DragEvent<HTMLDivElement>, item.id, 'right')}
                  onClick={() => handleRightClick(item.id)}
                  whileHover={!showResults && !isMatched ? { scale: 1.02 } : {}}
                  whileTap={!showResults && !isMatched ? { scale: 0.98 } : {}}
                  className={`
                    relative p-4 rounded-lg border-2 transition-all cursor-pointer
                    ${!showResults && !isMatched ? 'hover:border-blue-300 hover:shadow-md' : ''}
                    ${isSelected ? 'border-blue-500 bg-blue-50' : ''}
                    ${isMatched && !showResults ? 'border-green-300 bg-green-50' : ''}
                    ${dragOverRight === item.id ? 'border-blue-400 bg-blue-100' : ''}
                    ${!isMatched && !isSelected ? 'border-gray-200' : ''}
                  `}
                >
                  <div className="flex items-center gap-3">
                    <GripVertical size={16} className="text-gray-400 flex-shrink-0" />
                    <span className="font-medium text-gray-800">{item.content}</span>
                  </div>

                  {/* Match indicator */}
                  {matchedItem && (
                    <div className="mt-3 pt-3 border-t border-gray-200">
                      <div className="flex items-center gap-2 text-sm">
                        <Link2 size={14} className="text-gray-400" />
                        <span className="text-gray-600">{matchedItem.content}</span>
                      </div>
                    </div>
                  )}
                </motion.div>
              );
            })}
          </div>
        </div>
      </Card>

      {/* Results Section */}
      <AnimatePresence>
        {showResults && (
          <motion.div
            initial={{ opacity: 0, y: 20 }}
            animate={{ opacity: 1, y: 0 }}
            exit={{ opacity: 0, y: -20 }}
          >
            <Card className="p-6 bg-gradient-to-br from-blue-50 to-indigo-50 border-blue-200">
              <div className="text-center mb-6">
                <motion.div
                  initial={{ scale: 0 }}
                  animate={{ scale: 1 }}
                  transition={{ type: 'spring', stiffness: 200, delay: 0.2 }}
                  className={`inline-flex items-center justify-center w-20 h-20 rounded-full mb-4 ${
                    correctCount === leftItems.length
                      ? 'bg-gradient-to-br from-yellow-400 to-orange-500'
                      : 'bg-gradient-to-br from-blue-400 to-indigo-500'
                  }`}
                >
                  <Trophy size={40} className="text-white" />
                </motion.div>

                <h3 className="text-2xl font-bold text-gray-900 mb-2">
                  {correctCount === leftItems.length
                    ? '¡Perfecto!'
                    : correctCount >= leftItems.length * 0.7
                    ? '¡Muy bien!'
                    : '¡Sigue practicando!'}
                </h3>

                <p className="text-gray-600">
                  {correctCount} de {leftItems.length} emparejamientos correctos
                </p>
              </div>

              {/* Score Display */}
              <div className="grid grid-cols-3 gap-4 max-w-lg mx-auto mb-6">
                <div className="bg-white rounded-xl p-4 shadow-sm">
                  <Star className="w-6 h-6 text-blue-500 mx-auto mb-2" />
                  <p className="text-2xl font-bold text-blue-700">{score}</p>
                  <p className="text-sm text-blue-600">Puntuación</p>
                </div>

                <div className="bg-white rounded-xl p-4 shadow-sm">
                  <Target className="w-6 h-6 text-green-500 mx-auto mb-2" />
                  <p className="text-2xl font-bold text-green-700">{maxPoints}</p>
                  <p className="text-sm text-green-600">Máximo</p>
                </div>

                <div className="bg-white rounded-xl p-4 shadow-sm">
                  <Zap className="w-6 h-6 text-purple-500 mx-auto mb-2" />
                  <p className="text-2xl font-bold text-purple-700">
                    {Math.round((score / maxPoints) * 100)}%
                  </p>
                  <p className="text-sm text-purple-600">Precisión</p>
                </div>
              </div>
            </Card>
          </motion.div>
        )}
      </AnimatePresence>

      {/* Action Buttons */}
      <div className="flex justify-between items-center">
        <Button
          variant="outline"
          onClick={handleReset}
        >
          <RefreshCcw size={16} className="mr-2" />
          Reiniciar
        </Button>

        <div className="flex gap-3">
          {!showResults ? (
            <Button
              onClick={handleValidate}
              disabled={!allMatched}
            >
              Validar Emparejamientos
            </Button>
          ) : (
            <Button onClick={handleReset}>
              Intentar de Nuevo
            </Button>
          )}
        </div>
      </div>

      {/* Instructions */}
      {!allMatched && matches.length > 0 && !showResults && (
        <div className="text-center text-sm text-gray-500">
          <p>
            Arrastra elementos o haz clic para conectar. Tienes{' '}
            <span className="font-semibold text-blue-600">{leftItems.length - matches.length}</span>{' '}
            emparejamientos pendientes.
          </p>
        </div>
      )}

      {allMatched && !showResults && (
        <div className="text-center text-sm text-green-600">
          <p className="font-medium">Todos los elementos están emparejados. ¡Valida tu respuesta!</p>
        </div>
      )}
    </div>
  );
}

export default MatchingExercise;
