
import React, { useRef, useState, useEffect } from 'react';
import { INSTRUMENTS, BASS_NOTES, MIN_TEMPO, MAX_TEMPO, MIN_STEPS, MAX_STEPS } from '../constants';
import { PlayIcon, StopIcon, ClearIcon, UploadIcon, DownloadIcon, PlusIcon, MinusIcon, MuteIcon, UnmuteIcon } from './icons';
import { Grid, BassLineGrid } from '../types';
import { Modal } from './Modal';

interface SequencerProps {
    steps: number;
    grid: Grid;
    bassLine: BassLineGrid;
    isPlaying: boolean;
    tempo: number;
    currentStep: number | null;
    mutes: boolean[];
    drumVolume: number;
    bassVolume: number;
    setStep: (instrumentIndex: number, stepIndex: number, isActive: boolean) => void;
    setBassNote: (stepIndex: number, note: string) => void;
    clearPattern: () => void;
    setTempo: React.Dispatch<React.SetStateAction<number>>;
    handleStepsChange: (newSteps: number) => void;
    startPlayback: () => Promise<void>;
    stopPlayback: () => void;
    exportBeat: () => void;
    importBeat: (event: React.ChangeEvent<HTMLInputElement>) => void;
    toggleMute: (instrumentIndex: number) => void;
    handleDrumVolumeChange: (newVolume: number) => void;
    handleBassVolumeChange: (newVolume: number) => void;
    triggerSound: (instrumentName: string) => void;
    triggerBassNote: (note: string) => void;
}

const SequencerButton: React.FC<{ onClick?: () => void; children: React.ReactNode; className?: string; disabled?: boolean }> = ({ onClick, children, className, disabled }) => (
    <button
        onClick={onClick}
        disabled={disabled}
        className={`flex items-center justify-center gap-2 px-4 py-2 text-sm font-semibold text-slate-700 bg-white border border-slate-300 rounded-md shadow-sm hover:bg-slate-50 focus:outline-none focus:ring-2 focus:ring-orange-500 focus:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed transition-all ${className}`}
    >
        {children}
    </button>
);

export const Sequencer: React.FC<SequencerProps> = ({
    steps, grid, isPlaying, tempo, currentStep, mutes, bassLine,
    drumVolume, bassVolume,
    clearPattern, setTempo, handleStepsChange, setStep, setBassNote,
    startPlayback, stopPlayback, exportBeat, importBeat, toggleMute,
    handleDrumVolumeChange, handleBassVolumeChange, triggerSound, triggerBassNote
}) => {

    const fileInputRef = useRef<HTMLInputElement>(null);
    const [isDragging, setIsDragging] = useState(false);
    const [dragActivationState, setDragActivationState] = useState(false);
    const [dragStartRow, setDragStartRow] = useState<number | null>(null);

    const [isBassDragging, setIsBassDragging] = useState(false);
    const [bassDragActivationState, setBassDragActivationState] = useState(false);
    const [isClearModalOpen, setIsClearModalOpen] = useState(false);

    useEffect(() => {
        const handleMouseUp = () => {
            setIsDragging(false);
            setDragStartRow(null);
            setIsBassDragging(false);
        };
        window.addEventListener('mouseup', handleMouseUp);
        return () => window.removeEventListener('mouseup', handleMouseUp);
    }, []);


    const handleImportClick = () => {
        fileInputRef.current?.click();
    };

    const handleCellMouseDown = (instIndex: number, stepIndex: number) => {
        setIsDragging(true);
        setDragStartRow(instIndex);
        const newState = !grid[instIndex]?.[stepIndex];
        setDragActivationState(newState);
        setStep(instIndex, stepIndex, newState);
        if (newState && !isPlaying) {
            triggerSound(INSTRUMENTS[instIndex].name);
        }
    };

    const handleCellMouseEnter = (instIndex: number, stepIndex: number) => {
        if (isDragging && instIndex === dragStartRow) {
            setStep(instIndex, stepIndex, dragActivationState);
        }
    };

    const handleBassCellMouseDown = (noteName: string, stepIndex: number) => {
        const isCurrentlyActive = bassLine[stepIndex]?.includes(noteName);
        const newState = !isCurrentlyActive;
        setBassNote(stepIndex, noteName);
        setIsBassDragging(true);
        setBassDragActivationState(newState);
        if (newState && !isPlaying) {
            triggerBassNote(noteName);
        }
    };

    const handleBassCellMouseEnter = (noteName: string, stepIndex: number) => {
        if (isBassDragging) {
            const isCurrentlyActive = bassLine[stepIndex]?.includes(noteName);
            if (bassDragActivationState !== isCurrentlyActive) {
                setBassNote(stepIndex, noteName);
            }
        }
    };
    
    const incrementTempo = () => setTempo(t => Math.min(MAX_TEMPO, t + 1));
    const decrementTempo = () => setTempo(t => Math.max(MIN_TEMPO, t - 1));

    const handleTempoScroll = (e: React.WheelEvent<HTMLDivElement>) => {
        e.preventDefault();
        if (e.deltaY < 0) {
            decrementTempo();
        } else {
            incrementTempo();
        }
    };
    
    const incrementSteps = () => {
        const newSteps = steps + 4;
        if (newSteps <= MAX_STEPS) {
            handleStepsChange(newSteps);
        }
    };

    const decrementSteps = () => {
        const newSteps = steps - 4;
        if (newSteps >= MIN_STEPS) {
            handleStepsChange(newSteps);
        }
    };

    const handleClearConfirm = () => {
        clearPattern();
        setIsClearModalOpen(false);
    };

    return (
        <>
            <Modal
                isOpen={isClearModalOpen}
                onClose={() => setIsClearModalOpen(false)}
                onConfirm={handleClearConfirm}
                title="Clear Session"
            >
                <p>Are you sure you want to clear the session? This will erase all current progress.</p>
            </Modal>
            <div className={`bg-white p-4 sm:p-6 rounded-xl shadow-lg border border-slate-200 ${isDragging || isBassDragging ? 'select-none' : ''}`}>
                <div className="flex flex-wrap items-center justify-between gap-4 mb-6">
                    <div className="flex items-center gap-2">
                        {!isPlaying ? (
                            <SequencerButton onClick={startPlayback} title="Play">
                                <PlayIcon className="w-5 h-5" /> <span className="hidden lg:inline">Play</span>
                            </SequencerButton>
                        ) : (
                            <SequencerButton onClick={stopPlayback} title="Stop">
                                <StopIcon className="w-5 h-5" /> <span className="hidden lg:inline">Stop</span>
                            </SequencerButton>
                        )}
                        <SequencerButton onClick={() => setIsClearModalOpen(true)} title="Clear">
                            <ClearIcon className="w-5 h-5" /> <span className="hidden lg:inline">Clear</span>
                        </SequencerButton>
                    </div>
                    
                    <div className="flex items-center gap-x-6 gap-y-2 flex-wrap justify-center">
                        <div className="flex items-center gap-3">
                            <label htmlFor="tempo-display" className="text-sm font-medium text-slate-600">Tempo</label>
                            <div
                                className="flex items-center border border-slate-300 rounded-md shadow-sm"
                                onWheel={handleTempoScroll}
                                title="Scroll to adjust tempo"
                            >
                                <button
                                    onClick={decrementTempo}
                                    disabled={tempo <= MIN_TEMPO}
                                    className="p-2 text-slate-700 hover:bg-slate-50 disabled:opacity-50 disabled:cursor-not-allowed rounded-l-md focus:outline-none focus:ring-2 focus:ring-orange-500 focus:ring-offset-1"
                                    aria-label="Decrease tempo"
                                >
                                    <MinusIcon className="w-5 h-5" />
                                </button>
                                <span
                                    id="tempo-display"
                                    className="px-3 py-2 text-sm font-mono text-slate-700 w-24 text-center border-l border-r border-slate-300 bg-white"
                                >
                                    {tempo} BPM
                                </span>
                                <button
                                    onClick={incrementTempo}
                                    disabled={tempo >= MAX_TEMPO}
                                    className="p-2 text-slate-700 hover:bg-slate-50 disabled:opacity-50 disabled:cursor-not-allowed rounded-r-md focus:outline-none focus:ring-2 focus:ring-orange-500 focus:ring-offset-1"
                                    aria-label="Increase tempo"
                                >
                                    <PlusIcon className="w-5 h-5" />
                                </button>
                            </div>
                        </div>
                         <div className="flex items-center gap-3">
                            <label htmlFor="steps-display" className="text-sm font-medium text-slate-600">Steps</label>
                            <div className="flex items-center border border-slate-300 rounded-md shadow-sm">
                               <button
                                    onClick={decrementSteps}
                                    disabled={steps <= MIN_STEPS}
                                    className="p-2 text-slate-700 hover:bg-slate-50 disabled:opacity-50 disabled:cursor-not-allowed rounded-l-md focus:outline-none focus:ring-2 focus:ring-orange-500 focus:ring-offset-1"
                                    aria-label="Decrease steps by one tact (4 steps)"
                                >
                                    <MinusIcon className="w-5 h-5" />
                                </button>
                                 <span
                                    id="steps-display"
                                    className="px-3 py-2 text-sm font-mono text-slate-700 w-16 text-center border-l border-r border-slate-300 bg-white"
                                 >
                                    {steps}
                                </span>
                                <button
                                    onClick={incrementSteps}
                                    disabled={steps >= MAX_STEPS}
                                    className="p-2 text-slate-700 hover:bg-slate-50 disabled:opacity-50 disabled:cursor-not-allowed rounded-r-md focus:outline-none focus:ring-2 focus:ring-orange-500 focus:ring-offset-1"
                                    aria-label="Increase steps by one tact (4 steps)"
                                >
                                    <PlusIcon className="w-5 h-5" />
                                </button>
                            </div>
                        </div>
                    </div>

                     <div className="flex items-center gap-2">
                        <SequencerButton onClick={handleImportClick} title="Import">
                            <UploadIcon className="w-5 h-5" /> <span className="hidden lg:inline">Import</span>
                        </SequencerButton>
                         <input type="file" ref={fileInputRef} onChange={importBeat} accept=".json" className="hidden" />
                        <SequencerButton onClick={exportBeat} title="Export">
                            <DownloadIcon className="w-5 h-5" /> <span className="hidden lg:inline">Export</span>
                        </SequencerButton>
                    </div>
                </div>

                <div className="flex items-start gap-4">
                    <div className="flex flex-col items-center gap-2 pt-10">
                         <input
                            id="drum-volume"
                            type="range" min="0" max="1.5" step="0.01" value={drumVolume}
                            onChange={e => handleDrumVolumeChange(Number(e.target.value))}
                            className="w-4 h-48 appearance-none cursor-pointer bg-slate-200 rounded-lg [writing-mode:vertical-lr] [direction:rtl] accent-orange-500"
                            aria-orientation="vertical"
                        />
                        <label htmlFor="drum-volume" className="text-xs font-medium text-slate-500 tracking-wider">DRUMS</label>
                    </div>
                    <div className="flex-1 overflow-x-auto pb-2">
                        <div className="grid gap-1" style={{ gridTemplateColumns: `100px repeat(${steps}, 1fr)` }}>
                            {/* Header */}
                            <div className="sticky left-0 bg-white z-10"></div>
                            {Array.from({ length: steps }, (_, i) => (
                                <div key={`header-${i}`} className="text-center text-xs text-slate-400">
                                     {(i % 4 === 0) ? (i/4 + 1) : ''}
                                </div>
                            ))}
                            {/* Grid Rows */}
                            {INSTRUMENTS.map((instrument, instIndex) => (
                                <div className="contents group" key={instrument.name}>
                                    <div className={`sticky left-0 bg-white flex items-center justify-end pr-2 py-1 transition-opacity z-10 ${mutes[instIndex] ? 'opacity-60' : ''}`}>
                                        <button
                                            onClick={() => toggleMute(instIndex)}
                                            className="mr-1 p-1 rounded-full text-slate-400 hover:bg-slate-200 hover:text-slate-600 focus:ring-2 focus:ring-orange-500 transition-opacity"
                                            aria-label={mutes[instIndex] ? `Unmute ${instrument.name}` : `Mute ${instrument.name}`}
                                        >
                                            {mutes[instIndex] ? <MuteIcon className="w-4 h-4" /> : <UnmuteIcon className="w-4 h-4 opacity-0 group-hover:opacity-100 focus:opacity-100" />}
                                        </button>
                                        <span className="text-xs sm:text-sm font-bold text-slate-600 tracking-wider text-right">{instrument.name}</span>
                                    </div>
                                    {grid[instIndex]?.map((isActive, stepIndex) => {
                                        const isCurrent = currentStep === stepIndex;
                                        const isFourth = stepIndex % 4 === 0;
                                        return (
                                            <div
                                                key={`${instrument.name}-${stepIndex}`}
                                                className={`w-full aspect-square rounded-md cursor-pointer transition-all duration-100 border ${isFourth ? 'border-l-slate-300' : 'border-l-transparent'} min-w-0
                                                ${isActive ? 'bg-orange-500 border-orange-600' : 'bg-slate-200 hover:bg-slate-300 border-slate-300'}
                                                ${isCurrent ? 'ring-2 ring-blue-500 ring-offset-1' : ''}
                                                ${mutes[instIndex] ? 'opacity-60' : ''}`}
                                                onMouseDown={() => handleCellMouseDown(instIndex, stepIndex)}
                                                onMouseEnter={() => handleCellMouseEnter(instIndex, stepIndex)}
                                                onDragStart={(e) => e.preventDefault()}
                                            />
                                        )
                                    })}
                                </div>
                            ))}
                        </div>
                    </div>
                </div>
                {/* Bass Sequencer */}
                <div className="mt-8 pt-6 border-t border-slate-200 flex items-start gap-4">
                     <div className="flex flex-col items-center gap-2 pt-10">
                         <input
                            id="bass-volume"
                            type="range" min="0" max="1" step="0.01" value={bassVolume}
                            onChange={e => handleBassVolumeChange(Number(e.target.value))}
                            className="w-4 h-48 appearance-none cursor-pointer bg-slate-200 rounded-lg [writing-mode:vertical-lr] [direction:rtl] accent-purple-500"
                            aria-orientation="vertical"
                        />
                        <label htmlFor="bass-volume" className="text-xs font-medium text-slate-500 tracking-wider">BASS</label>
                    </div>
                    <div className="flex-1 overflow-x-auto pb-2">
                        <div className="grid gap-px" style={{ gridTemplateColumns: `100px repeat(${steps}, 1fr)` }}>
                             {/* Header */}
                            <div className="sticky left-0 bg-white z-10"></div>
                            {Array.from({ length: steps }, (_, i) => (
                                <div key={`bass-header-${i}`} className="text-center text-xs text-slate-400 h-4 flex items-end justify-center">
                                    {(i % 4 === 0) ? <span className="mb-1">{(i/4 + 1)}</span> : ''}
                                </div>
                            ))}
                            {/* Bass Grid Rows (reversed to have low notes at the bottom) */}
                            {[...BASS_NOTES].reverse().map((note) => (
                                <div className="contents" key={note.name}>
                                    <div className={`sticky left-0 bg-white flex items-center justify-end pr-2 py-0 z-10 ${note.isSharp ? 'bg-slate-100' : 'bg-white'}`}>
                                        <span className={`text-xs font-mono tracking-wider text-right ${note.isSharp ? 'text-slate-500' : 'text-slate-700 font-bold'}`}>{note.name}</span>
                                    </div>
                                    {Array.from({ length: steps }).map((_, stepIndex) => {
                                        const isSelected = bassLine[stepIndex]?.includes(note.name);
                                        const isCurrent = currentStep === stepIndex;
                                        return (
                                            <div
                                                key={`${note.name}-${stepIndex}`}
                                                className={`w-full h-5 cursor-pointer transition-colors duration-100 relative
                                                ${isSelected ? 'bg-purple-500' : note.isSharp ? 'bg-slate-200 hover:bg-slate-300' : 'bg-slate-100 hover:bg-slate-300'}
                                                `}
                                                onMouseDown={() => handleBassCellMouseDown(note.name, stepIndex)}
                                                onMouseEnter={() => handleBassCellMouseEnter(note.name, stepIndex)}
                                                onDragStart={(e) => e.preventDefault()}
                                            >
                                               {isCurrent && <div className="absolute inset-0 bg-blue-500/30"></div>}
                                               {stepIndex > 0 && stepIndex % 4 === 0 && <div className="absolute inset-y-0 left-0 w-px bg-slate-300"></div>}
                                            </div>
                                        )
                                    })}
                                </div>
                            ))}
                        </div>
                    </div>
                </div>
            </div>
        </>
    );
};