/**
 * Speech Bubble System Component
 *
 * Canvas-based speech bubble editor using Fabric.js
 * Supports auto-placement, manual editing, and multiple bubble types
 */

import type { JSX } from 'react';
import { useState, useCallback, useEffect, useRef } from 'react';
import {
  MessageSquare,
  RefreshCw,
  ChevronLeft,
  ChevronRight,
  Type,
  Palette,
  MousePointer2,
  Sparkles,
} from 'lucide-react';
import { Button } from '@/components/ui/button';
import { useComicStore } from '@/store/comicStore';
import { autoPlacePanelBubbles, DEFAULT_BUBBLE_STYLE } from '@/services/bubbleEngine';
import type { SpeechBubble, BubbleType } from '@/types';

const BUBBLE_TYPES: Array<{ value: BubbleType; label: string; icon: string }> = [
  { value: 'normal', label: 'Speech', icon: '💬' },
  { value: 'thought', label: 'Thought', icon: '💭' },
  { value: 'shout', label: 'Shout', icon: '📢' },
  { value: 'whisper', label: 'Whisper', icon: '🤫' },
  { value: 'narration', label: 'Narration', icon: '📖' },
];

interface BubbleEditorProps {
  bubble: SpeechBubble;
  isSelected: boolean;
  onSelect: () => void;
  onUpdate: (updates: Partial<SpeechBubble>) => void;
  scale: number;
}

function BubbleEditor({
  bubble,
  isSelected,
  onSelect,
  onUpdate,
  scale,
}: BubbleEditorProps): JSX.Element {
  const [isEditing, setIsEditing] = useState(false);
  const [editText, setEditText] = useState(bubble.text);
  const [isDragging, setIsDragging] = useState(false);
  const [dragOffset, setDragOffset] = useState({ x: 0, y: 0 });

  const handleSave = () => {
    onUpdate({ text: editText });
    setIsEditing(false);
  };

  const handleMouseDown = (e: React.MouseEvent) => {
    e.stopPropagation();
    onSelect();
    
    // Start dragging
    setIsDragging(true);
    setDragOffset({
      x: e.clientX,
      y: e.clientY,
    });
  };

  const handleMouseMove = (e: React.MouseEvent) => {
    if (!isDragging) return;
    
    e.preventDefault();
    const dx = (e.clientX - dragOffset.x) / scale;
    const dy = (e.clientY - dragOffset.y) / scale;
    
    onUpdate({
      position: {
        x: Math.max(0, bubble.position.x + dx),
        y: Math.max(0, bubble.position.y + dy),
      },
    });
    
    setDragOffset({
      x: e.clientX,
      y: e.clientY,
    });
  };

  const handleMouseUp = () => {
    setIsDragging(false);
  };

  const getBubbleShape = () => {
    const { width, height } = bubble.size;
    const r = bubble.style.borderRadius;

    // Create path based on bubble type
    let path = '';

    switch (bubble.type) {
      case 'thought':
        // Cloud shape with circles
        path = `M ${r} 0 L ${width - r} 0 Q ${width} 0 ${width} ${r} L ${width} ${height - r} Q ${width} ${height} ${width - r} ${height} L ${r} ${height} Q 0 ${height} 0 ${height - r} L 0 ${r} Q 0 0 ${r} 0 Z`;
        break;
      case 'shout':
        // Spiky shape
        path = `M ${r} 0 L ${width / 2 - 10} 0 L ${width / 2} -10 L ${width / 2 + 10} 0 L ${width - r} 0 Q ${width} 0 ${width} ${r} L ${width} ${height / 2 - 10} L ${width + 10} ${height / 2} L ${width} ${height / 2 + 10} L ${width} ${height - r} Q ${width} ${height} ${width - r} ${height} L ${r} ${height} Q 0 ${height} 0 ${height - r} L 0 ${height / 2 + 10} L -10 ${height / 2} L 0 ${height / 2 - 10} L 0 ${r} Q 0 0 ${r} 0 Z`;
        break;
      default:
        // Standard rounded rect
        path = `M ${r} 0 L ${width - r} 0 Q ${width} 0 ${width} ${r} L ${width} ${height - r} Q ${width} ${height} ${width - r} ${height} L ${r} ${height} Q 0 ${height} 0 ${height - r} L 0 ${r} Q 0 0 ${r} 0 Z`;
    }

    return path;
  };

  return (
    <div
      className={`absolute ${isSelected ? 'z-10' : 'z-0'}`}
      style={{
        left: bubble.position.x * scale,
        top: bubble.position.y * scale,
        width: bubble.size.width * scale,
        height: bubble.size.height * scale,
      }}
    >
      {/* Bubble Shape */}
      <svg
        width={bubble.size.width * scale}
        height={bubble.size.height * scale + 20}
        className="absolute inset-0 pointer-events-none"
        style={{ overflow: 'visible' }}
      >
        {/* Main bubble */}
        <path
          d={getBubbleShape()}
          fill={bubble.style.backgroundColor}
          stroke={bubble.style.borderColor}
          strokeWidth={bubble.style.borderWidth * scale}
          strokeDasharray={bubble.type === 'whisper' ? '5,5' : undefined}
          transform={`scale(${scale})`}
        />
        {/* Tail for speech/thought */}
        {bubble.type !== 'narration' && (
          <path
            d={`M ${bubble.size.width / 2} ${bubble.size.height} L ${bubble.tailTarget.x - bubble.position.x} ${bubble.tailTarget.y - bubble.position.y + bubble.size.height}`}
            stroke={bubble.style.borderColor}
            strokeWidth={bubble.style.borderWidth * scale}
            fill="none"
          />
        )}
      </svg>

      {/* Drag Handle (invisible border for dragging) */}
      {!isEditing && (
        <div
          className="absolute inset-0 z-20 cursor-grab active:cursor-grabbing"
          onMouseDown={handleMouseDown}
          onMouseMove={handleMouseMove}
          onMouseUp={handleMouseUp}
          onMouseLeave={handleMouseUp}
          title="Drag to move, double-click text to edit"
        />
      )}

      {/* Text Content */}
      <div
        className="absolute inset-0 flex items-center justify-center p-2 cursor-text"
        style={{
          fontSize: bubble.style.fontSize * scale,
          fontFamily: bubble.style.fontFamily,
          color: bubble.style.textColor,
        }}
        onClick={(e) => {
          e.stopPropagation();
          onSelect();
        }}
        onDoubleClick={() => setIsEditing(true)}
      >
        {isEditing ? (
          <textarea
            value={editText}
            onChange={(e) => setEditText(e.target.value)}
            onBlur={handleSave}
            onKeyDown={(e) => {
              if (e.key === 'Enter' && !e.shiftKey) {
                e.preventDefault();
                handleSave();
              }
            }}
            className="w-full h-full bg-transparent resize-none outline-none text-center"
            autoFocus
          />
        ) : (
          <span className="text-center break-words pointer-events-none">{bubble.text}</span>
        )}
      </div>

      {/* Selection handles */}
      {isSelected && (
        <>
          <div className="absolute -top-1 -left-1 w-2 h-2 bg-primary rounded-full" />
          <div className="absolute -top-1 -right-1 w-2 h-2 bg-primary rounded-full" />
          <div className="absolute -bottom-1 -left-1 w-2 h-2 bg-primary rounded-full" />
          <div className="absolute -bottom-1 -right-1 w-2 h-2 bg-primary rounded-full" />
        </>
      )}
    </div>
  );
}

interface PanelCanvasProps {
  panelImage: string | undefined;
  bubbles: SpeechBubble[];
  selectedBubbleId: string | null;
  onSelectBubble: (id: string | null) => void;
  onUpdateBubble: (id: string, updates: Partial<SpeechBubble>) => void;
}

function PanelCanvas({
  panelImage,
  bubbles,
  selectedBubbleId,
  onSelectBubble,
  onUpdateBubble,
}: PanelCanvasProps): JSX.Element {
  const containerRef = useRef<HTMLDivElement>(null);
  const [scale, setScale] = useState(1);

  useEffect(() => {
    // Calculate scale to fit canvas in container
    if (containerRef.current) {
      const containerWidth = containerRef.current.clientWidth;
      setScale(containerWidth / 800); // Base width of 800px
    }
  }, []);

  return (
    <div
      ref={containerRef}
      className="relative bg-gray-100 overflow-hidden cursor-crosshair"
      style={{ aspectRatio: '4/3' }}
      onClick={() => onSelectBubble(null)}
    >
      {/* Panel Background Image */}
      {panelImage ? (
        <img
          src={panelImage}
          alt="Panel"
          className="absolute inset-0 w-full h-full object-contain"
        />
      ) : (
        <div className="absolute inset-0 flex items-center justify-center text-muted-foreground">
          No panel image
        </div>
      )}

      {/* Speech Bubbles */}
      {bubbles.map((bubble) => (
        <BubbleEditor
          key={bubble.id}
          bubble={bubble}
          isSelected={bubble.id === selectedBubbleId}
          onSelect={() => onSelectBubble(bubble.id)}
          onUpdate={(updates) => onUpdateBubble(bubble.id, updates)}
          scale={scale}
        />
      ))}
    </div>
  );
}

export function SpeechBubbleSystem(): JSX.Element {
  const {
    script,
    pageLayouts,
    panelImages,
    speechBubbles,
    setSpeechBubbles,
    characters,
    userMode,
    setWorkflowStep,
  } = useComicStore();

  const [currentPageIndex, setCurrentPageIndex] = useState(0);
  const [currentPanelIndex, setCurrentPanelIndex] = useState(0);
  const [selectedBubbleId, setSelectedBubbleId] = useState<string | null>(null);
  const [isAutoPlacing, setIsAutoPlacing] = useState(false);

  // Get current page and panel
  const currentPage = pageLayouts[currentPageIndex];
  const currentPanel = currentPage?.panels[currentPanelIndex];
  const currentPanelImage = currentPanel ? panelImages[currentPanel.panelId] : undefined;
  const currentBubbles = currentPanel ? speechBubbles[currentPanel.panelId] || [] : [];

  // Get panel data from script
  const getPanelData = useCallback((panelId: string) => {
    if (!script) return null;
    for (const page of script.pages) {
      const panel = page.panels.find(p => p.panelId === panelId);
      if (panel) return panel;
    }
    return null;
  }, [script]);

  const currentPanelData = currentPanel ? getPanelData(currentPanel.panelId) : null;

  const handleAutoPlace = useCallback(() => {
    if (!currentPanelData) return;

    setIsAutoPlacing(true);
    const bubbles = autoPlacePanelBubbles(
      currentPanelData,
      800, // panel width
      600 // panel height
    );

    setSpeechBubbles(currentPanel.panelId, bubbles);
    setIsAutoPlacing(false);
  }, [currentPanel, currentPanelData, characters, setSpeechBubbles]);

  const handleUpdateBubble = useCallback((bubbleId: string, updates: Partial<SpeechBubble>) => {
    if (!currentPanel) return;

    const updatedBubbles = currentBubbles.map(b =>
      b.id === bubbleId ? { ...b, ...updates } : b
    );
    setSpeechBubbles(currentPanel.panelId, updatedBubbles);
  }, [currentPanel, currentBubbles, setSpeechBubbles]);

  const handleChangeBubbleType = useCallback((type: BubbleType) => {
    if (!selectedBubbleId) return;
    handleUpdateBubble(selectedBubbleId, { type });
  }, [selectedBubbleId, handleUpdateBubble]);

  const handleProceed = useCallback(() => {
    setWorkflowStep('complete');
  }, [setWorkflowStep]);

  // Calculate total progress
  const totalPanels = pageLayouts.reduce((acc, page) => acc + page.panels.length, 0);
  const completedPanels = Object.keys(speechBubbles).length;
  const allCompleted = totalPanels > 0 && completedPanels === totalPanels;

  if (!script || pageLayouts.length === 0) {
    return (
      <div className="flex items-center justify-center h-full">
        <p className="text-muted-foreground">
          Create a layout first before adding speech bubbles.
        </p>
      </div>
    );
  }

  return (
    <div className="max-w-6xl mx-auto space-y-6">
      {/* Header */}
      <div className="flex items-center justify-between">
        <div>
          <h2 className="text-2xl font-bold flex items-center gap-2">
            <MessageSquare className="w-6 h-6" />
            Speech Bubbles
          </h2>
          <p className="text-muted-foreground">
            Page {currentPageIndex + 1} of {pageLayouts.length} • Panel {currentPanelIndex + 1} of {currentPage?.panels.length}
          </p>
        </div>

        <div className="flex gap-2">
          <Button
            variant="outline"
            onClick={handleAutoPlace}
            disabled={!currentPanelData || isAutoPlacing}
          >
            {isAutoPlacing ? (
              <RefreshCw className="w-4 h-4 mr-2 animate-spin" />
            ) : (
              <Sparkles className="w-4 h-4 mr-2" />
            )}
            Auto-Place
          </Button>
          <Button onClick={handleProceed}>
            {allCompleted ? 'Finish' : 'Skip for Now'}
          </Button>
        </div>
      </div>

      {/* Progress */}
      <div className="space-y-2">
        <div className="h-2 bg-muted rounded-full overflow-hidden">
          <div
            className="h-full bg-primary transition-all duration-500"
            style={{ width: `${(completedPanels / totalPanels) * 100}%` }}
          />
        </div>
        <p className="text-center text-sm text-muted-foreground">
          {completedPanels} of {totalPanels} panels have speech bubbles
        </p>
      </div>

      {/* Navigation */}
      <div className="flex items-center justify-center gap-4">
        <Button
          variant="outline"
          size="sm"
          onClick={() => {
            if (currentPanelIndex > 0) {
              setCurrentPanelIndex(currentPanelIndex - 1);
            } else if (currentPageIndex > 0) {
              setCurrentPageIndex(currentPageIndex - 1);
              setCurrentPanelIndex(pageLayouts[currentPageIndex - 1].panels.length - 1);
            }
          }}
          disabled={currentPageIndex === 0 && currentPanelIndex === 0}
        >
          <ChevronLeft className="w-4 h-4" />
          Previous
        </Button>

        <span className="text-sm text-muted-foreground">
          {currentPanelData?.description.substring(0, 50)}...
        </span>

        <Button
          variant="outline"
          size="sm"
          onClick={() => {
            if (currentPanelIndex < (currentPage?.panels.length || 0) - 1) {
              setCurrentPanelIndex(currentPanelIndex + 1);
            } else if (currentPageIndex < pageLayouts.length - 1) {
              setCurrentPageIndex(currentPageIndex + 1);
              setCurrentPanelIndex(0);
            }
          }}
          disabled={
            currentPageIndex === pageLayouts.length - 1 &&
            currentPanelIndex === (currentPage?.panels.length || 0) - 1
          }
        >
          Next
          <ChevronRight className="w-4 h-4" />
        </Button>
      </div>

      {/* Main Editor */}
      <div className="grid grid-cols-1 lg:grid-cols-4 gap-6">
        {/* Canvas */}
        <div className="lg:col-span-3">
          <PanelCanvas
            panelImage={currentPanelImage?.url}
            bubbles={currentBubbles}
            selectedBubbleId={selectedBubbleId}
            onSelectBubble={setSelectedBubbleId}
            onUpdateBubble={handleUpdateBubble}
          />
        </div>

        {/* Sidebar Tools */}
        <div className="space-y-4">
          {/* Bubble Type Selector */}
          <div className="p-4 bg-muted/50 rounded-lg border">
            <div className="flex items-center gap-2 mb-3">
              <Type className="w-4 h-4" />
              <h3 className="font-semibold">Bubble Type</h3>
            </div>
            <div className="grid grid-cols-2 gap-2">
              {BUBBLE_TYPES.map((type) => (
                <button
                  key={type.value}
                  onClick={() => handleChangeBubbleType(type.value)}
                  disabled={!selectedBubbleId}
                  className={`p-2 rounded-lg border text-sm transition-colors ${
                    selectedBubbleId && currentBubbles.find(b => b.id === selectedBubbleId)?.type === type.value
                      ? 'border-primary bg-primary/10'
                      : 'bg-background hover:bg-muted'
                  } ${!selectedBubbleId ? 'opacity-50 cursor-not-allowed' : ''}`}
                >
                  <span className="mr-1">{type.icon}</span>
                  {type.label}
                </button>
              ))}
            </div>
            {!selectedBubbleId && (
              <p className="text-xs text-muted-foreground mt-2 text-center">
                Select a bubble to edit
              </p>
            )}
          </div>

          {/* Style Editor (Pro Mode) */}
          {userMode === 'professional' && selectedBubbleId && (
            <div className="p-4 bg-muted/50 rounded-lg border">
              <div className="flex items-center gap-2 mb-3">
                <Palette className="w-4 h-4" />
                <h3 className="font-semibold">Style</h3>
              </div>
              <div className="space-y-3">
                <div>
                  <label className="text-xs text-muted-foreground">Background</label>
                  <input
                    type="color"
                    value={currentBubbles.find(b => b.id === selectedBubbleId)?.style.backgroundColor || '#ffffff'}
                    onChange={(e) => handleUpdateBubble(selectedBubbleId, {
                      style: { ...DEFAULT_BUBBLE_STYLE, backgroundColor: e.target.value }
                    })}
                    className="w-full h-8 rounded cursor-pointer"
                  />
                </div>
                <div>
                  <label className="text-xs text-muted-foreground">Border</label>
                  <input
                    type="color"
                    value={currentBubbles.find(b => b.id === selectedBubbleId)?.style.borderColor || '#000000'}
                    onChange={(e) => handleUpdateBubble(selectedBubbleId, {
                      style: { ...DEFAULT_BUBBLE_STYLE, borderColor: e.target.value }
                    })}
                    className="w-full h-8 rounded cursor-pointer"
                  />
                </div>
              </div>
            </div>
          )}

          {/* Instructions */}
          <div className="p-4 bg-blue-50 rounded-lg border border-blue-200">
            <div className="flex items-start gap-2">
              <MousePointer2 className="w-4 h-4 text-blue-600 mt-0.5" />
              <div className="text-sm text-blue-800">
                <p className="font-medium">How to edit:</p>
                <ul className="list-disc list-inside mt-1 space-y-1 text-xs">
                  <li>Click bubble to select</li>
                  <li>Drag bubble to reposition</li>
                  <li>Double-click text to edit</li>
                  <li>Click canvas to deselect</li>
                </ul>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}
