import { useDroppable, useDraggable } from '@dnd-kit/core'
import type { Track, PlacedSound } from '@/pages/SequencerPage'
import { Button } from '@/components/ui/button'
import { Trash2, Volume2 } from 'lucide-react'
import { useState, forwardRef, useRef, useEffect } from 'react'

interface SequencerCanvasProps {
  tracks: Track[]
  duration: number
  zoom: number
  currentTime: number
  isPlaying: boolean
  onScroll?: () => void
  draggedItem?: any // Current dragged item from parent
  dragOverInfo?: {trackId: string, x: number} | null // Drag over position info
  onRemoveSound: (soundId: string, trackId: string) => void
  timeIntervals: {minorIntervals: number[], majorIntervals: number[], minorInterval: number, majorInterval: number}
}

interface TrackRowProps {
  track: Track
  duration: number
  zoom: number
  isPlaying: boolean
  currentTime: number
  draggedItem?: any // Current dragged item
  dragOverInfo?: {trackId: string, x: number} | null // Drag over position info
  onRemoveSound: (soundId: string, trackId: string) => void
  timeIntervals: {minorIntervals: number[], majorIntervals: number[], minorInterval: number, majorInterval: number}
}

interface PlacedSoundItemProps {
  sound: PlacedSound
  zoom: number
  trackId: string
  onRemove: (soundId: string) => void
  minorInterval: number
}

function PlacedSoundItem({ sound, zoom, trackId, onRemove, minorInterval }: PlacedSoundItemProps) {
  const {
    attributes,
    listeners,
    setNodeRef,
    transform,
    isDragging,
  } = useDraggable({
    id: sound.id,
    data: {
      type: 'placed-sound',
      ...sound,
      trackId,
    },
  })

  const style = transform ? {
    transform: `translate3d(${transform.x}px, ${transform.y}px, 0)`,
  } : undefined

  const width = (sound.duration / 1000) * zoom  // Convert ms to seconds for zoom calculation
  // Ensure placed sounds are positioned at snapped locations using current minor interval
  const startTimeSeconds = sound.startTime / 1000
  const snappedStartTime = Math.round(startTimeSeconds / minorInterval) * minorInterval
  const left = Math.max(0, snappedStartTime) * zoom

  const formatTime = (seconds: number): string => {
    const mins = Math.floor(seconds / 60)
    const secs = Math.floor(seconds % 60)
    return `${mins}:${secs.toString().padStart(2, '0')}`
  }

  return (
    <div
      ref={setNodeRef}
      style={{
        ...style,
        position: 'absolute',
        left: `${left}px`,
        width: `${width}px`,
        top: '8px',
        bottom: '8px',
      }}
      {...listeners}
      {...attributes}
      className={`
        bg-primary/20 border-2 border-primary/40 rounded
        flex items-center justify-between px-2 text-xs
        cursor-grab active:cursor-grabbing
        hover:bg-primary/30 hover:border-primary/60
        group transition-colors
        ${isDragging ? 'opacity-50 z-10' : 'z-0'}
      `}
      title={`${sound.name} (${formatTime(sound.duration / 1000)})`}
    >
      <div className="flex items-center gap-1 min-w-0 flex-1">
        <Volume2 className="h-3 w-3 flex-shrink-0 text-primary" />
        <span className="truncate font-medium text-primary">
          {sound.name}
        </span>
      </div>
      
      <Button
        variant="ghost"
        size="sm"
        onClick={(e) => {
          e.stopPropagation()
          onRemove(sound.id)
        }}
        className="h-6 w-6 p-0 opacity-0 group-hover:opacity-100 transition-opacity text-destructive hover:text-destructive hover:bg-destructive/10"
        title="Remove sound"
      >
        <Trash2 className="h-3 w-3" />
      </Button>
    </div>
  )
}

function TrackRow({ track, duration, zoom, isPlaying, currentTime, draggedItem, dragOverInfo, onRemoveSound, timeIntervals }: TrackRowProps) {
  const playheadPosition = (currentTime / 1000) * zoom  // Convert ms to seconds for zoom calculation

  const { isOver, setNodeRef: setDropRef } = useDroppable({
    id: `track-${track.id}`,
    data: {
      type: 'track',
      trackId: track.id,
    },
  })

  const handleRemoveSound = (soundId: string) => {
    onRemoveSound(soundId, track.id)
  }

  const { minorIntervals, majorIntervals } = timeIntervals

  return (
    <div className="relative" style={{ height: '80px' }}>
      <div
        ref={setDropRef}
        id={`track-${track.id}`}
        className={`
          h-full border-b border-border/50
          relative overflow-hidden
          ${isOver ? 'bg-accent/30' : 'bg-muted/10'}
          transition-colors
        `}
      >
        {/* Grid lines for time markers */}
        <div className="absolute inset-0 pointer-events-none">
          {/* Minor grid lines */}
          {minorIntervals.map((time) => (
            <div
              key={`minor-${time}`}
              className="absolute top-0 bottom-0 w-px bg-border/30"
              style={{ left: `${time * zoom}px` }}
            />
          ))}
          {/* Major grid lines */}
          {majorIntervals.map((time) => (
            <div
              key={`major-${time}`}
              className="absolute top-0 bottom-0 w-px bg-border/60"
              style={{ left: `${time * zoom}px` }}
            />
          ))}
        </div>

        {/* Precise drag preview (dragOverInfo.x is already snapped) */}
        {draggedItem && dragOverInfo && dragOverInfo.trackId === track.id && (() => {
          const soundDurationMs = draggedItem.type === 'sound' 
            ? draggedItem.sound.duration  // Already in ms
            : draggedItem.duration         // Already in ms
          const soundDurationSeconds = soundDurationMs / 1000
          
          // dragOverInfo.x is already snapped in the parent component
          const startTimeSeconds = dragOverInfo.x / zoom
          const endTimeSeconds = startTimeSeconds + soundDurationSeconds
          const durationSeconds = duration / 1000
          const isValidPosition = startTimeSeconds >= 0 && endTimeSeconds <= durationSeconds
          
          return (
            <div
              className={`absolute top-2 bottom-2 border-2 border-dashed rounded pointer-events-none z-10 flex items-center px-2 ${
                isValidPosition 
                  ? 'border-primary/60 bg-primary/10' 
                  : 'border-red-500/60 bg-red-500/10'
              }`}
              style={{
                left: `${Math.max(0, dragOverInfo.x)}px`,
                width: `${Math.max(60, soundDurationSeconds * zoom)}px`,
              }}
            >
              <div className={`text-xs truncate font-medium ${
                isValidPosition ? 'text-primary/80' : 'text-red-500/80'
              }`}>
                {draggedItem.type === 'sound' 
                  ? (draggedItem.sound.name || draggedItem.sound.filename)
                  : draggedItem.name
                }
                {!isValidPosition && ' (Invalid)'}
              </div>
            </div>
          )
        })()}

        {/* Playhead */}
        {isPlaying && (
          <div
            className="absolute top-0 bottom-0 w-0.5 bg-red-500 pointer-events-none z-30"
            style={{ left: `${playheadPosition}px` }}
          />
        )}

        {/* Placed sounds */}
        {track.sounds.map((sound) => (
          <PlacedSoundItem
            key={sound.id}
            sound={sound}
            zoom={zoom}
            trackId={track.id}
            onRemove={handleRemoveSound}
            minorInterval={timeIntervals.minorInterval}
          />
        ))}
      </div>
    </div>
  )
}

export const SequencerCanvas = forwardRef<HTMLDivElement, SequencerCanvasProps>(({
  tracks,
  duration,
  zoom,
  currentTime,
  isPlaying,
  onScroll,
  draggedItem,
  dragOverInfo,
  onRemoveSound,
  timeIntervals,
}, ref) => {
  const totalWidth = (duration / 1000) * zoom  // Convert ms to seconds for zoom calculation
  const timelineRef = useRef<HTMLDivElement>(null)
  
  // Add a fallback droppable for the entire canvas area
  const { setNodeRef: setCanvasDropRef } = useDroppable({
    id: 'sequencer-canvas',
    data: {
      type: 'canvas',
    },
  })

  const { minorIntervals, majorIntervals } = timeIntervals

  const handleTracksScroll = (e: React.UIEvent<HTMLDivElement>) => {
    // Sync timeline horizontal scroll with tracks
    if (timelineRef.current) {
      const scrollLeft = e.currentTarget.scrollLeft
      // Only update if different to prevent scroll fighting
      if (Math.abs(timelineRef.current.scrollLeft - scrollLeft) > 1) {
        timelineRef.current.scrollLeft = scrollLeft
      }
    }
    // Call the original scroll handler for vertical sync
    onScroll?.()
  }

  return (
    <div ref={setCanvasDropRef} className="h-full flex flex-col overflow-hidden">
      {/* Time ruler */}
      <div className="h-8 bg-muted/50 border-b border-border/50 flex-shrink-0 overflow-hidden">
        <div
          ref={timelineRef}
          className="h-full overflow-x-auto [&::-webkit-scrollbar]:hidden"
          style={{ 
            scrollbarWidth: 'none',
            msOverflowStyle: 'none'
          }}
        >
          <div className="relative h-full" style={{ width: `${totalWidth}px` }}>
            {/* Minor time markers */}
            {minorIntervals.map((time) => (
              <div key={`ruler-minor-${time}`} className="absolute top-0 bottom-0" style={{ left: `${time * zoom}px` }}>
                <div className="absolute top-0 w-px h-2 bg-border/40" />
              </div>
            ))}
            
            {/* Major time markers with labels */}
            {majorIntervals.map((time) => {
              const formatTime = (seconds: number): string => {
                if (seconds < 60) {
                  // For times under 1 minute, show seconds with decimal places if needed
                  return seconds < 10 && seconds % 1 !== 0 
                    ? seconds.toFixed(1) + 's'
                    : Math.floor(seconds) + 's'
                } else {
                  // For times over 1 minute, show MM:SS format
                  const mins = Math.floor(seconds / 60)
                  const secs = Math.floor(seconds % 60)
                  return `${mins}:${secs.toString().padStart(2, '0')}`
                }
              }

              return (
                <div key={`ruler-major-${time}`} className="absolute top-0 bottom-0" style={{ left: `${time * zoom}px` }}>
                  <div className="absolute top-0 w-px h-3 bg-border/60" />
                  <div className="absolute top-4 text-xs text-muted-foreground font-mono whitespace-nowrap">
                    {formatTime(time)}
                  </div>
                </div>
              )
            })}
            
            {/* Playhead in ruler */}
            {isPlaying && (
              <div
                className="absolute top-0 bottom-0 w-0.5 bg-red-500 z-30"
                style={{ left: `${(currentTime / 1000) * zoom}px` }}
              />
            )}
          </div>
        </div>
      </div>

      {/* Tracks */}
      <div 
        ref={ref}
        className="flex-1 overflow-auto"
        onScroll={handleTracksScroll}
      >
        <div style={{ width: `${totalWidth}px`, paddingBottom: '52px' }}>
          {tracks.map((track) => (
            <TrackRow
              key={track.id}
              track={track}
              duration={duration}
              zoom={zoom}
              isPlaying={isPlaying}
              currentTime={currentTime}
              draggedItem={draggedItem}
              dragOverInfo={dragOverInfo}
              onRemoveSound={onRemoveSound}
              timeIntervals={timeIntervals}
            />
          ))}
        </div>
      </div>
    </div>
  )
})

SequencerCanvas.displayName = 'SequencerCanvas'