/**
 * SchemaElementPopup.tsx
 * 
 * A popup component that displays LinkML schema element previews when clicking on
 * class/slot/enum names in the Imports/Exports accordion sections.
 * 
 * Features:
 * - Draggable (drag from header)
 * - Minimizable (collapse to title bar only)
 * - Resizable (drag edges and corners)
 * - Shows preview info for classes, slots, and enums
 * - "Go to" button to navigate to full element view
 */

import React, { useEffect, useLayoutEffect, useState, useRef, useCallback } from 'react';
import { linkmlSchemaService } from '../../lib/linkml/linkml-schema-service';
import { isTargetInsideAny } from '../../utils/dom';
import './SchemaElementPopup.css';

export type SchemaElementType = 'class' | 'slot' | 'enum';

interface SchemaElementPopupProps {
  /** The element name to look up */
  elementName: string;
  /** Type of element */
  elementType: SchemaElementType;
  /** Called when user wants to close the popup */
  onClose: () => void;
  /** Called when user clicks "Go to" button */
  onNavigate: (elementName: string, elementType: SchemaElementType) => void;
  /** Initial position (optional, defaults to center) */
  initialPosition?: { x: number; y: number };
}

interface Position {
  x: number;
  y: number;
}

interface Size {
  width: number;
  height: number;
}

type ResizeDirection = 'n' | 's' | 'e' | 'w' | 'ne' | 'nw' | 'se' | 'sw' | null;

// Minimum panel dimensions
const MIN_WIDTH = 300;
const MIN_HEIGHT = 150;
const DEFAULT_WIDTH = 400;
const DEFAULT_HEIGHT = 320;

/**
 * Unified element info structure
 */
interface ElementInfo {
  name: string;
  type: SchemaElementType;
  description?: string;
  uri?: string;
  parentClass?: string;
  range?: string;
  required?: boolean;
  multivalued?: boolean;
  slotCount?: number;
  valueCount?: number;
  mappings?: {
    exact?: string[];
    close?: string[];
    related?: string[];
  };
}

export const SchemaElementPopup: React.FC<SchemaElementPopupProps> = ({
  elementName,
  elementType,
  onClose,
  onNavigate,
  initialPosition,
}) => {
  const [elementInfo, setElementInfo] = useState<ElementInfo | null>(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);
  
  // Draggable state
  const [position, setPosition] = useState<Position | null>(initialPosition || null);
  const [isPositioned, setIsPositioned] = useState(!!initialPosition);
  const [isDragging, setIsDragging] = useState(false);
  const dragStartRef = useRef<{ x: number; y: number; posX: number; posY: number } | null>(null);
  const panelRef = useRef<HTMLDivElement>(null);
  
  // Minimized state
  const [isMinimized, setIsMinimized] = useState(false);
  
  // Resize state
  const [size, setSize] = useState<Size>({ width: DEFAULT_WIDTH, height: DEFAULT_HEIGHT });
  const [isResizing, setIsResizing] = useState(false);
  const [resizeDirection, setResizeDirection] = useState<ResizeDirection>(null);
  const resizeStartRef = useRef<{ 
    x: number; 
    y: number; 
    width: number; 
    height: number;
    posX: number;
    posY: number;
  } | null>(null);

  // Load element information
  useEffect(() => {
    const loadInfo = async () => {
      setLoading(true);
      setError(null);
      
      try {
        let info: ElementInfo | null = null;
        
        if (elementType === 'class') {
          const semanticInfo = await linkmlSchemaService.getClassSemanticInfo(elementName);
          if (semanticInfo) {
            info = {
              name: semanticInfo.className,
              type: 'class',
              description: semanticInfo.description,
              uri: semanticInfo.classUri,
              parentClass: semanticInfo.parentClass,
              slotCount: semanticInfo.slots?.length || 0,
              mappings: semanticInfo.mappings,
            };
          }
        } else if (elementType === 'slot') {
          const slotInfo = await linkmlSchemaService.getSlotInfo(elementName);
          if (slotInfo) {
            info = {
              name: slotInfo.name,
              type: 'slot',
              description: slotInfo.description,
              uri: slotInfo.slotUri,
              range: slotInfo.range,
              required: slotInfo.required,
              multivalued: slotInfo.multivalued,
            };
          }
        } else if (elementType === 'enum') {
          const enumInfo = await linkmlSchemaService.getEnumSemanticInfo(elementName);
          if (enumInfo) {
            info = {
              name: enumInfo.enumName,
              type: 'enum',
              description: enumInfo.description,
              // EnumSemanticInfo doesn't have URI - leave undefined
              valueCount: enumInfo.values?.length || 0,
            };
          }
        }
        
        if (info) {
          setElementInfo(info);
        } else {
          setError(`Could not find ${elementType} "${elementName}"`);
        }
      } catch (err) {
        console.error('[SchemaElementPopup] Error loading element info:', err);
        setError(`Failed to load: ${err}`);
      } finally {
        setLoading(false);
      }
    };
    
    loadInfo();
  }, [elementName, elementType]);

  // Center the popup on initial load if no position provided
  useLayoutEffect(() => {
    if (!initialPosition && panelRef.current && !position) {
      const rect = panelRef.current.getBoundingClientRect();
      setPosition({
        x: (window.innerWidth - rect.width) / 2,
        y: (window.innerHeight - rect.height) / 3,
      });
      setIsPositioned(true);
    }
  }, [initialPosition, position]);

  // Drag handlers
  const handleMouseDown = useCallback((e: React.MouseEvent) => {
    if (isTargetInsideAny(e.target, ['.schema-popup__close', '.schema-popup__minimize', '.schema-popup__navigate'])) {
      return;
    }
    
    e.preventDefault();
    setIsDragging(true);
    
    const panel = panelRef.current;
    if (panel) {
      const rect = panel.getBoundingClientRect();
      const currentX = position?.x ?? rect.left;
      const currentY = position?.y ?? rect.top;
      
      dragStartRef.current = {
        x: e.clientX,
        y: e.clientY,
        posX: currentX,
        posY: currentY,
      };
    }
  }, [position]);

  const handleMouseMove = useCallback((e: MouseEvent) => {
    if (!isDragging || !dragStartRef.current) return;
    
    const deltaX = e.clientX - dragStartRef.current.x;
    const deltaY = e.clientY - dragStartRef.current.y;
    
    const newX = dragStartRef.current.posX + deltaX;
    const newY = dragStartRef.current.posY + deltaY;
    
    const maxX = window.innerWidth - 100;
    const maxY = window.innerHeight - 50;
    
    setPosition({
      x: Math.max(0, Math.min(newX, maxX)),
      y: Math.max(0, Math.min(newY, maxY)),
    });
  }, [isDragging]);

  const handleMouseUp = useCallback(() => {
    setIsDragging(false);
    dragStartRef.current = null;
  }, []);

  // Add/remove global mouse event listeners for dragging
  useEffect(() => {
    if (isDragging) {
      window.addEventListener('mousemove', handleMouseMove);
      window.addEventListener('mouseup', handleMouseUp);
      document.body.style.cursor = 'grabbing';
      document.body.style.userSelect = 'none';
    } else {
      document.body.style.cursor = '';
      document.body.style.userSelect = '';
    }
    
    return () => {
      window.removeEventListener('mousemove', handleMouseMove);
      window.removeEventListener('mouseup', handleMouseUp);
      document.body.style.cursor = '';
      document.body.style.userSelect = '';
    };
  }, [isDragging, handleMouseMove, handleMouseUp]);

  // Toggle minimize
  const toggleMinimize = useCallback(() => {
    setIsMinimized(prev => !prev);
  }, []);

  // Resize handlers
  const handleResizeMouseDown = useCallback((direction: ResizeDirection) => (e: React.MouseEvent) => {
    e.preventDefault();
    e.stopPropagation();
    
    setIsResizing(true);
    setResizeDirection(direction);
    
    const panel = panelRef.current;
    if (panel) {
      const rect = panel.getBoundingClientRect();
      resizeStartRef.current = {
        x: e.clientX,
        y: e.clientY,
        width: size.width,
        height: size.height,
        posX: position?.x ?? rect.left,
        posY: position?.y ?? rect.top,
      };
    }
  }, [size, position]);

  const handleResizeMouseMove = useCallback((e: MouseEvent) => {
    if (!isResizing || !resizeStartRef.current || !resizeDirection) return;
    
    const deltaX = e.clientX - resizeStartRef.current.x;
    const deltaY = e.clientY - resizeStartRef.current.y;
    
    let newWidth = resizeStartRef.current.width;
    let newHeight = resizeStartRef.current.height;
    let newX = resizeStartRef.current.posX;
    let newY = resizeStartRef.current.posY;
    
    if (resizeDirection.includes('e')) {
      newWidth = Math.max(MIN_WIDTH, resizeStartRef.current.width + deltaX);
    }
    if (resizeDirection.includes('w')) {
      const potentialWidth = resizeStartRef.current.width - deltaX;
      if (potentialWidth >= MIN_WIDTH) {
        newWidth = potentialWidth;
        newX = resizeStartRef.current.posX + deltaX;
      }
    }
    
    if (resizeDirection.includes('s')) {
      newHeight = Math.max(MIN_HEIGHT, resizeStartRef.current.height + deltaY);
    }
    if (resizeDirection.includes('n')) {
      const potentialHeight = resizeStartRef.current.height - deltaY;
      if (potentialHeight >= MIN_HEIGHT) {
        newHeight = potentialHeight;
        newY = resizeStartRef.current.posY + deltaY;
      }
    }
    
    setSize({ width: newWidth, height: newHeight });
    
    if (resizeDirection.includes('w') || resizeDirection.includes('n')) {
      setPosition({ x: newX, y: newY });
    }
  }, [isResizing, resizeDirection]);

  const handleResizeMouseUp = useCallback(() => {
    setIsResizing(false);
    setResizeDirection(null);
    resizeStartRef.current = null;
  }, []);

  // Add/remove global mouse event listeners for resizing
  useEffect(() => {
    if (isResizing) {
      window.addEventListener('mousemove', handleResizeMouseMove);
      window.addEventListener('mouseup', handleResizeMouseUp);
      document.body.style.userSelect = 'none';
    }
    
    return () => {
      window.removeEventListener('mousemove', handleResizeMouseMove);
      window.removeEventListener('mouseup', handleResizeMouseUp);
      if (!isDragging) {
        document.body.style.userSelect = '';
      }
    };
  }, [isResizing, handleResizeMouseMove, handleResizeMouseUp, isDragging]);

  // Handle navigate button click
  const handleNavigate = useCallback(() => {
    onNavigate(elementName, elementType);
    onClose();
  }, [elementName, elementType, onNavigate, onClose]);

  // Render type badge
  const renderTypeBadge = (type: SchemaElementType) => {
    const colors: Record<SchemaElementType, string> = {
      'class': '#3B82F6',    // Blue
      'slot': '#10B981',     // Green
      'enum': '#F59E0B',     // Amber
    };
    return (
      <span 
        className="schema-popup__type-badge"
        style={{ backgroundColor: colors[type] }}
      >
        {type}
      </span>
    );
  };

  // Calculate panel style
  const panelStyle: React.CSSProperties = {
    width: size.width,
    height: isMinimized ? 'auto' : size.height,
    visibility: isPositioned ? 'visible' : 'hidden',
    ...(position && {
      position: 'fixed',
      left: position.x,
      top: position.y,
    }),
  };

  return (
    <div 
      ref={panelRef}
      className={`schema-popup ${isMinimized ? 'schema-popup--minimized' : ''} ${isDragging ? 'schema-popup--dragging' : ''}`}
      style={panelStyle}
    >
      {/* Header */}
      <div 
        className="schema-popup__header"
        onMouseDown={handleMouseDown}
      >
        <div className="schema-popup__title">
          <code className="schema-popup__name">{elementName}</code>
          {renderTypeBadge(elementType)}
        </div>
        <div className="schema-popup__controls">
          <button 
            className="schema-popup__minimize"
            onClick={toggleMinimize}
            title={isMinimized ? 'Expand' : 'Minimize'}
          >
            {isMinimized ? '□' : '−'}
          </button>
          <button 
            className="schema-popup__close"
            onClick={onClose}
            title="Close"
          >
            ×
          </button>
        </div>
      </div>
      
      {/* Content */}
      {!isMinimized && (
        <div className="schema-popup__content">
          {loading && (
            <div className="schema-popup__loading">
              Loading {elementType} information...
            </div>
          )}
          
          {error && (
            <div className="schema-popup__error">
              {error}
            </div>
          )}
          
          {!loading && !error && elementInfo && (
            <>
              {/* Description */}
              {elementInfo.description && (
                <div className="schema-popup__section">
                  <span className="schema-popup__section-label">Description</span>
                  <p className="schema-popup__description">{elementInfo.description}</p>
                </div>
              )}
              
              {/* URI */}
              {elementInfo.uri && (
                <div className="schema-popup__section">
                  <span className="schema-popup__section-label">URI</span>
                  <code className="schema-popup__uri">{elementInfo.uri}</code>
                </div>
              )}
              
              {/* Parent class (for classes) */}
              {elementInfo.parentClass && (
                <div className="schema-popup__section">
                  <span className="schema-popup__section-label">Parent Class</span>
                  <code className="schema-popup__value">{elementInfo.parentClass}</code>
                </div>
              )}
              
              {/* Range (for slots) */}
              {elementInfo.range && (
                <div className="schema-popup__section">
                  <span className="schema-popup__section-label">Range</span>
                  <code className="schema-popup__value">{elementInfo.range}</code>
                </div>
              )}
              
              {/* Properties (for slots) */}
              {elementInfo.type === 'slot' && (
                <div className="schema-popup__section schema-popup__properties">
                  {elementInfo.required !== undefined && (
                    <span className={`schema-popup__prop ${elementInfo.required ? 'schema-popup__prop--true' : ''}`}>
                      {elementInfo.required ? 'required' : 'optional'}
                    </span>
                  )}
                  {elementInfo.multivalued !== undefined && (
                    <span className={`schema-popup__prop ${elementInfo.multivalued ? 'schema-popup__prop--true' : ''}`}>
                      {elementInfo.multivalued ? 'multivalued' : 'single-valued'}
                    </span>
                  )}
                </div>
              )}
              
              {/* Slot count (for classes) */}
              {elementInfo.slotCount !== undefined && elementInfo.slotCount > 0 && (
                <div className="schema-popup__section">
                  <span className="schema-popup__section-label">Slots</span>
                  <span className="schema-popup__count">{elementInfo.slotCount} slots</span>
                </div>
              )}
              
              {/* Value count (for enums) */}
              {elementInfo.valueCount !== undefined && elementInfo.valueCount > 0 && (
                <div className="schema-popup__section">
                  <span className="schema-popup__section-label">Values</span>
                  <span className="schema-popup__count">{elementInfo.valueCount} permissible values</span>
                </div>
              )}
              
              {/* Mappings (summary) */}
              {elementInfo.mappings && (
                (elementInfo.mappings.exact?.length || 
                 elementInfo.mappings.close?.length || 
                 elementInfo.mappings.related?.length) ? (
                  <div className="schema-popup__section">
                    <span className="schema-popup__section-label">Mappings</span>
                    <div className="schema-popup__mappings">
                      {elementInfo.mappings.exact?.length ? (
                        <span className="schema-popup__mapping-badge schema-popup__mapping-badge--exact">
                          {elementInfo.mappings.exact.length} exact
                        </span>
                      ) : null}
                      {elementInfo.mappings.close?.length ? (
                        <span className="schema-popup__mapping-badge schema-popup__mapping-badge--close">
                          {elementInfo.mappings.close.length} close
                        </span>
                      ) : null}
                      {elementInfo.mappings.related?.length ? (
                        <span className="schema-popup__mapping-badge schema-popup__mapping-badge--related">
                          {elementInfo.mappings.related.length} related
                        </span>
                      ) : null}
                    </div>
                  </div>
                ) : null
              )}
              
              {/* Navigate button */}
              <div className="schema-popup__actions">
                <button 
                  className="schema-popup__navigate"
                  onClick={handleNavigate}
                >
                  Go to {elementType} →
                </button>
              </div>
            </>
          )}
        </div>
      )}
      
      {/* Resize handles */}
      {!isMinimized && (
        <>
          <div className="schema-popup__resize schema-popup__resize--n" onMouseDown={handleResizeMouseDown('n')} />
          <div className="schema-popup__resize schema-popup__resize--s" onMouseDown={handleResizeMouseDown('s')} />
          <div className="schema-popup__resize schema-popup__resize--e" onMouseDown={handleResizeMouseDown('e')} />
          <div className="schema-popup__resize schema-popup__resize--w" onMouseDown={handleResizeMouseDown('w')} />
          <div className="schema-popup__resize schema-popup__resize--ne" onMouseDown={handleResizeMouseDown('ne')} />
          <div className="schema-popup__resize schema-popup__resize--nw" onMouseDown={handleResizeMouseDown('nw')} />
          <div className="schema-popup__resize schema-popup__resize--se" onMouseDown={handleResizeMouseDown('se')} />
          <div className="schema-popup__resize schema-popup__resize--sw" onMouseDown={handleResizeMouseDown('sw')} />
        </>
      )}
    </div>
  );
};

export default SchemaElementPopup;
