import React, { useRef } from 'react';
import { KGTrack } from '../../core/track/KGTrack';
import { KGMidiRegion } from '../../core/region/KGMidiRegion';
import TrackGridItem from './TrackGridItem';
import { Playhead } from '../common';
import type { RegionUI } from '../interfaces';
import { DEBUG_MODE } from '../../constants';
import { KGMainContentState } from '../../core/state/KGMainContentState';
import { isModifierKeyPressed } from '../../util/osUtil';
import { CreateRegionCommand, ResizeRegionCommand, MoveRegionCommand } from '../../core/commands';
import { KGCore } from '../../core/KGCore';
import { generateNewRegionName } from '../../util/miscUtil';

interface TrackGridPanelProps {
  tracks: KGTrack[];
  regions: RegionUI[];
  maxBars: number;
  timeSignature: { numerator: number; denominator: number };
  draggedTrackIndex: number | null;
  dragOverTrackIndex: number | null;
  selectedRegionId: string | null;
  onRegionCreated: (trackIndex: number, region: RegionUI, midiRegion: KGMidiRegion) => void;
  onRegionUpdated?: (regionId: string, updates: Partial<RegionUI>, expectedModelUpdates?: { startBeat: number, length: number }) => void;
  onRegionClick?: (regionId: string) => void;
  onOpenPianoRoll?: (regionId: string) => void;
}

const TrackGridPanel: React.FC<TrackGridPanelProps> = ({
  tracks,
  regions,
  maxBars,
  timeSignature,
  draggedTrackIndex,
  dragOverTrackIndex,
  selectedRegionId,
  onRegionCreated,
  onRegionUpdated,
  onRegionClick,
  onOpenPianoRoll
}) => {
  const gridContainerRef = useRef<HTMLDivElement>(null);

  // Utility function to create a region at a specific position
  const createRegionAtPosition = (e: React.MouseEvent<HTMLDivElement>, trackIndex: number) => {
    // Get the grid container element
    const gridContainer = e.currentTarget.closest('.grid-container');
    if (!gridContainer) return;
    
    // Get the grid container's bounding rectangle
    const gridRect = gridContainer.getBoundingClientRect();
    
    // Calculate the relative X position within the grid
    const relativeX = e.clientX - gridRect.left;
    
    // Calculate the width of each bar
    const barWidth = gridContainer.clientWidth / maxBars;
    
    // Calculate which bar was clicked (0-indexed)
    const barIndex = Math.floor(relativeX / barWidth);
    
    // Add 1 to convert to 1-indexed bar number
    const barNumber = barIndex + 1;
    
    // Get the track and its ID
    const track = tracks[trackIndex];
    const trackId = track.getId().toString();
    
    if (DEBUG_MODE.TRACK_GRID_PANEL) {
      console.log(`Creating region on track ${trackIndex + 1}, bar ${barNumber}`);
    }
    
    // Get beats per bar from the time signature
    const beatsPerBar = timeSignature.numerator;
    
    // Check for overlapping regions before creating a new one
    const newRegionStartBeat = (barNumber - 1) * beatsPerBar;
    const newRegionEndBeat = newRegionStartBeat + beatsPerBar - 1;
    
    const existingRegions = track.getRegions();
    const hasOverlap = existingRegions.some(region => {
      const existingStart = region.getStartFromBeat();
      const existingEnd = existingStart + region.getLength() - 1;
      return newRegionStartBeat <= existingEnd && newRegionEndBeat >= existingStart;
    });
    
    if (hasOverlap) {
      if (DEBUG_MODE.TRACK_GRID_PANEL) {
        console.log(`Cannot create region at bar ${barNumber}: overlaps with existing region`);
      }
      alert('Cannot create region: overlaps with existing region');
      return; // Don't create the region if it overlaps
    }
    
    // Create and execute the region creation command
    const command = CreateRegionCommand.fromBarCoordinates(
      trackId,
      trackIndex,
      barNumber,
      1, // Default to 1 bar length
      beatsPerBar,
      generateNewRegionName(trackId)
    );
    
    KGCore.instance().executeCommand(command);
    
    // Get the created region for the UI callback
    const createdRegion = command.getCreatedRegion();
    if (createdRegion) {
      // Create the region UI object for the parent component
      const newRegionUI: RegionUI = {
        id: createdRegion.getId(),
        trackId: trackId,
        trackIndex,
        barNumber,
        length: 1,
        name: createdRegion.getName()
      };
      
      // Notify parent about the new region (for UI state updates)
      onRegionCreated(trackIndex, newRegionUI, createdRegion);
    }
  };

  // Handle double click on track grid to create region
  const handleTrackGridDoubleClick = (e: React.MouseEvent<HTMLDivElement>, trackIndex: number) => {
    // Only allow double-click creation in pointer mode
    if (KGMainContentState.instance().getActiveTool() === 'pencil') {
      return;
    }
    createRegionAtPosition(e, trackIndex);
  };

  // Handle single click on track grid for pencil mode or modifier+click
  const handleTrackGridClick = (e: React.MouseEvent<HTMLDivElement>, trackIndex: number) => {
    // Create region on single click in pencil mode OR when modifier key is pressed
    if (KGMainContentState.instance().getActiveTool() === 'pencil' || isModifierKeyPressed(e)) {
      createRegionAtPosition(e, trackIndex);
    }
  };

  // Handle region resize during drag
  const handleRegionResize = (regionId: string, newBarNumber: number, newLength: number) => {
    // This is just for live visual updates, we don't update the model yet
    if (DEBUG_MODE.TRACK_GRID_PANEL) {
      console.log(`Resizing region ${regionId} to barNumber ${newBarNumber}, length ${newLength}`);
    }
  };

  // Handle region resize end
  const handleRegionResizeEnd = (regionId: string, finalBarNumber: number, finalLength: number) => {
    // Now we update the model with the final rounded values
    if (DEBUG_MODE.TRACK_GRID_PANEL) {
      console.log(`Finished resizing region ${regionId} to barNumber ${finalBarNumber}, length ${finalLength}`);
    }
    
    // Find the region
    const region = regions.find(r => r.id === regionId);
    if (!region) return;
    
    // Calculate new start and length in beats
    const beatsPerBar = timeSignature.numerator;
    const newStartBeat = (finalBarNumber - 1) * beatsPerBar;
    const newLengthInBeats = finalLength * beatsPerBar;
    
    // Find the track that contains this region
    const track = tracks.find(t => t.getId().toString() === region.trackId);
    if (!track) return;
    
    // Update the region in the track's model
    const trackRegions = track.getRegions();
    const midiRegion = trackRegions.find(r => r.getId() === regionId) as KGMidiRegion | undefined;
    
    if (midiRegion) {
      const oldStartBeat = midiRegion.getStartFromBeat();
      const oldBarNumber = region.barNumber;
      
      if (DEBUG_MODE.TRACK_GRID_PANEL) {
        console.log(`Updating KGRegion model - Before: startBeat=${oldStartBeat}, length=${midiRegion.getLength()}`);
        console.log(`Bar numbers - old: ${oldBarNumber}, new: ${finalBarNumber}`);
      }
      
      // Use command pattern to update the region position and length (note adjustments handled inside command)
      try {
        const command = ResizeRegionCommand.fromBarCoordinates(
          regionId,
          finalBarNumber,
          finalLength,
          timeSignature
        );
        
        KGCore.instance().executeCommand(command);

        if (DEBUG_MODE.TRACK_GRID_PANEL) {
          console.log(`Executed ResizeRegionCommand: region ${regionId} resized using command pattern`);
          
          // Verify the command worked
          const updatedRegion = track.getRegions().find(r => r.getId() === regionId);
          console.log(`Verified region in track: ${updatedRegion ? 'found' : 'not found'}, startBeat=${updatedRegion?.getStartFromBeat()}, length=${updatedRegion?.getLength()}`);
        }
      } catch (error) {
        console.error('Error resizing region:', error);
        return;
      }
    }
    
    // Update the region in the parent component with expected model values
    if (onRegionUpdated) {
      onRegionUpdated(
        regionId, 
        { barNumber: finalBarNumber, length: finalLength },
        { startBeat: newStartBeat, length: newLengthInBeats }
      );
    }
  };

  // Handle region drag during movement
  const handleRegionDrag = (regionId: string, newBarNumber: number, trackIndex: number) => {
    // This is just for live visual updates, we don't update the model yet
    if (DEBUG_MODE.TRACK_GRID_PANEL) {
      console.log(`Dragging region ${regionId} to barNumber ${newBarNumber}, trackIndex ${trackIndex}`);
    }
    
    // We don't need to update any temporary state in the parent component anymore
    // The region will follow the mouse directly using transform in the TrackGridItem component
  };

  // Handle region drag end
  const handleRegionDragEnd = (regionId: string, finalBarNumber: number, finalTrackIndex: number) => {
    // Now we update the model with the final rounded values
    if (DEBUG_MODE.TRACK_GRID_PANEL) {
      console.log(`Finished dragging region ${regionId} to barNumber ${finalBarNumber}, trackIndex ${finalTrackIndex}`);
    }
    
    // Find the region
    const region = regions.find(r => r.id === regionId);
    if (!region) return;
    
    // Get the target track
    const targetTrack = tracks[finalTrackIndex];
    if (!targetTrack) return;
    
    // Use command pattern to move the region
    try {
      const command = MoveRegionCommand.fromBarCoordinates(
        regionId,
        finalBarNumber,
        targetTrack.getId().toString(),
        finalTrackIndex,
        timeSignature
      );
      
      KGCore.instance().executeCommand(command);

      if (DEBUG_MODE.TRACK_GRID_PANEL) {
        console.log(`Executed MoveRegionCommand: region ${regionId} moved using command pattern`);
        
        // Verify the command worked
        const movedRegion = command.getTargetRegion();
        console.log(`Verified region: ${movedRegion ? 'found' : 'not found'}, startBeat=${movedRegion?.getStartFromBeat()}, trackId=${movedRegion?.getTrackId()}`);
      }
    } catch (error) {
      console.error('Error moving region:', error);
      return;
    }
    
    // Calculate new start in beats for UI update
    const beatsPerBar = timeSignature.numerator;
    const startBeat = (finalBarNumber - 1) * beatsPerBar;
    
    // Update the region in the parent component with expected model values
    if (onRegionUpdated) {
      // Find the updated region to get its length
      const updatedTrack = tracks[finalTrackIndex];
      const updatedRegions = updatedTrack.getRegions();
      const updatedRegion = updatedRegions.find(r => r.getId() === regionId);
      
      onRegionUpdated(
        regionId, 
        { 
          trackId: targetTrack.getId().toString(), 
          trackIndex: finalTrackIndex, 
          barNumber: finalBarNumber 
        },
        { 
          startBeat, 
          length: updatedRegion ? updatedRegion.getLength() : 0 
        }
      );
    }
  };

  // Handle region click
  const handleRegionClick = (regionId: string) => {
    if (DEBUG_MODE.TRACK_GRID_PANEL) {
      console.log(`Region clicked in panel: ${regionId}`);
    }
    
    // Find the region
    const region = regions.find(r => r.id === regionId);
    if (!region) return;
    
    // Find the track that contains this region
    const track = tracks.find(t => t.getId().toString() === region.trackId);
    if (!track) return;
    
    // Find the region in the track's model
    const trackRegions = track.getRegions();
    const midiRegion = trackRegions.find(r => r.getId() === regionId) as KGMidiRegion | undefined;
    
    if (midiRegion && DEBUG_MODE.TRACK_GRID_PANEL) {
      console.log(`Found region in model: ${midiRegion.getId()}, trackId=${midiRegion.getTrackId()}, name=${midiRegion.getName()}`);
    }
    
    // Notify parent about the click
    if (onRegionClick) {
      onRegionClick(regionId);
    }
  };

  return (
    <div className="grid-container" ref={gridContainerRef}>
      {/* Playhead */}
      <Playhead context="main-grid" />
      
      {/* Track grids */}
      {tracks.map((track, index) => (
        <TrackGridItem
          key={track.getId()}
          track={track}
          index={index}
          isDragging={draggedTrackIndex === index}
          isDragOver={dragOverTrackIndex === index}
          regions={regions}
          maxBars={maxBars}
          selectedRegionId={selectedRegionId}
          gridContainerRef={gridContainerRef}
          onDoubleClick={handleTrackGridDoubleClick}
          onClick={handleTrackGridClick}
          onRegionResize={handleRegionResize}
          onRegionResizeEnd={handleRegionResizeEnd}
          onRegionDrag={handleRegionDrag}
          onRegionDragEnd={handleRegionDragEnd}
          onRegionClick={handleRegionClick}
          onOpenPianoRoll={onOpenPianoRoll}
          allTracks={tracks}
        />
      ))}
    </div>
  );
};

export default TrackGridPanel; 