fix the left to right resizing of selections they're horrible it always ends up clearing the selection I think when zoomed in or out either way its just not right please fix and return entire code no commentary ty

using System;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using NAudio.Wave;
using Timer = System.Windows.Forms.Timer;

namespace ByteBreath
{
    public partial class AudioEditorForm : Form
    {
        private DataSetMaker _datasetMaker;
        public Color mainColor;
        public Color accentColor;
        public Color textColor;

        private float[] audioSamples; // interleaved samples: totalFrames * channels
        private WaveFormat waveFormat;
        private string currentFilePath;
        public string SelectionPath;
        private bool isSelecting = false;
        private bool isMovingSelection = false;
        private int selectionStart = -1; // frame index
        private int selectionEnd = -1;   // frame index

        private int sampleRate;

        private WaveOutEvent waveOut;
        private BufferedWaveProvider bufferedWaveProvider;

        private Timer playbackTimer;
        private long playStartFrame = 0;
        private long playEndFrame = 0;
        private bool isPlaying = false;

        private int viewStartFrame = 0; // viewing frames start (for zooming and scrolling)
        private int viewFrames = 0;
        private const int minViewFrames = 1000;
        private const int maxViewFramesFactor = 1;

        private bool isMouseInWaveform = false;

        // New fields for right-click panning
        private bool isPanning = false;
        private int lastPanMouseX = 0;

        // New fields for selection moving
        private int moveSelectionStartFrameDiff = 0;
        private int lastMouseX = 0;

        // New fields for selection resizing
        private bool isResizingLeft = false;
        private bool isResizingRight = false;
        private const int selectionEdgeSensitivity = 5; // pixels

        public AudioEditorForm(DataSetMaker dataSetMaker)
        {
            InitializeComponent();
            waveformPanel.Paint += WaveformPanel_Paint;
            waveformPanel.MouseDown += WaveformPanel_MouseDown;
            waveformPanel.MouseMove += WaveformPanel_MouseMove;
            waveformPanel.MouseUp += WaveformPanel_MouseUp;
            waveformPanel.MouseWheel += WaveformPanel_MouseWheel;
            waveformPanel.MouseEnter += WaveformPanel_MouseEnter;
            waveformPanel.MouseLeave += WaveformPanel_MouseLeave;
            waveformPanel.KeyDown += WaveformPanel_KeyDown;

            playbackTimer = new Timer();
            playbackTimer.Interval = 30;
            playbackTimer.Tick += PlaybackTimer_Tick;

            this.KeyPreview = true;
            this.KeyDown += AudioEditorForm_KeyDown;

            btnSave.Enabled = false;
            TopMost = true;
            _datasetMaker = dataSetMaker;
        }

        private void WaveformPanel_MouseEnter(object sender, EventArgs e)
        {
            isMouseInWaveform = true;
            waveformPanel.Focus();
        }

        private void WaveformPanel_MouseLeave(object sender, EventArgs e)
        {
            if (!isSelecting && !isMovingSelection && !isResizingLeft && !isResizingRight)
            {
                waveformPanel.Cursor = Cursors.Default;
            }
            isMouseInWaveform = false;
        }

        private void WaveformPanel_MouseWheel(object sender, MouseEventArgs e)
        {
            if (isMouseInWaveform)
                ZoomWaveform(e);
        }

        private void ZoomWaveform(MouseEventArgs e)
        {
            if (audioSamples == null || audioSamples.Length == 0)
                return;

            int panelWidth = waveformPanel.ClientSize.Width;
            if (panelWidth <= 0)
                return;

            if (viewFrames == 0)
            {
                int totalFrames = audioSamples.Length / waveFormat.Channels;
                viewFrames = totalFrames;
                viewStartFrame = 0;
            }

            float zoomFactor = 1.0f - (e.Delta / 1200.0f);
            if (zoomFactor <= 0) zoomFactor = 0.1f;

            int newViewFrames = (int)(viewFrames * zoomFactor);

            int minFrames = minViewFrames;
            int maxFrames = (audioSamples.Length / waveFormat.Channels) * maxViewFramesFactor;
            if (maxFrames < minFrames) maxFrames = minFrames;

            if (newViewFrames < minFrames) newViewFrames = minFrames;
            if (newViewFrames > maxFrames) newViewFrames = maxFrames;

            if (newViewFrames == viewFrames)
                return;

            double mouseRatio = (double)e.X / panelWidth;
            mouseRatio = Math.Clamp(mouseRatio, 0.0, 1.0);

            long mouseFrame = viewStartFrame + (long)(mouseRatio * viewFrames);
            long newViewStartFrame = mouseFrame - (long)(mouseRatio * newViewFrames);

            if (newViewStartFrame < 0) newViewStartFrame = 0;
            if (newViewStartFrame + newViewFrames > audioSamples.Length / waveFormat.Channels)
                newViewStartFrame = (audioSamples.Length / waveFormat.Channels) - newViewFrames;
            if (newViewStartFrame < 0)
                newViewStartFrame = 0;

            viewStartFrame = (int)newViewStartFrame;
            viewFrames = newViewFrames;

            waveformPanel.Invalidate();
        }

        private void SplitAndSaveChunks(string filePath, TimeSpan totalDuration, WaveFormat originalFormat)
        {
            try
            {
                using var reader = new AudioFileReader(filePath);
                int channels = reader.WaveFormat.Channels;
                int sampleRateLocal = reader.WaveFormat.SampleRate;
                int samplesPerSecond = sampleRateLocal * channels;
                int chunkSeconds = 20 * 60; // 20 minutes in seconds
                int chunkSamples = samplesPerSecond * chunkSeconds;

                string directory = Path.GetDirectoryName(filePath);
                string originalFileName = Path.GetFileNameWithoutExtension(filePath);
                string extension = Path.GetExtension(filePath);

                int totalSamples = (int)(reader.Length / 4); // float samples
                int totalChunks = (totalSamples + chunkSamples - 1) / chunkSamples;

                for (int chunkIndex = 0; chunkIndex < totalChunks; chunkIndex++)
                {
                    int samplesToRead = Math.Min(chunkSamples, totalSamples - chunkIndex * chunkSamples);
                    float[] chunkBuffer = new float[samplesToRead];

                    reader.Position = chunkIndex * chunkSamples * 4;
                    int readSamples = 0;
                    int offset = 0;
                    while (offset < samplesToRead)
                    {
                        int needed = samplesToRead - offset;
                        int readNow = reader.Read(chunkBuffer, offset, needed);
                        if (readNow == 0)
                            break;
                        offset += readNow;
                    }

                    string chunkFileName = $"{originalFileName}_Part{chunkIndex + 1}{extension}";
                    string chunkFilePath = Path.Combine(directory, chunkFileName);

                    using (var writer = new WaveFileWriter(chunkFilePath, originalFormat))
                    {
                        if (originalFormat.Encoding == WaveFormatEncoding.IeeeFloat)
                        {
                            writer.WriteSamples(chunkBuffer, 0, offset);
                        }
                        else if (originalFormat.BitsPerSample == 16)
                        {
                            short[] int16Samples = new short[offset];
                            for (int i = 0; i < offset; i++)
                            {
                                float sample = chunkBuffer[i];
                                sample = Math.Max(-1f, Math.Min(1f, sample));
                                int16Samples[i] = (short)(sample * short.MaxValue);
                            }
                            byte[] bytes = new byte[int16Samples.Length * 2];
                            Buffer.BlockCopy(int16Samples, 0, bytes, 0, bytes.Length);
                            writer.Write(bytes, 0, bytes.Length);
                        }
                        else
                        {
                            MessageBox.Show("Unsupported bit depth: " + originalFormat.BitsPerSample);
                            return;
                        }
                    }
                }

                // Delete original large file
                try
                {
                    waveOut?.Stop();
                    waveOut?.Dispose();
                    waveOut = null;
                }
                catch { }
                try
                {
                    File.Delete(filePath);
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Failed to delete original large file: " + ex.Message);
                }

                MessageBox.Show("Audio file split into 20 minute chunks and original file deleted.", "Split Complete", MessageBoxButtons.OK, MessageBoxIcon.Information);
                this.Close(); // Close current editor form since the original file is deleted.
            }
            catch (Exception ex)
            {
                MessageBox.Show("Failed to split and save chunks: " + ex.Message);
            }
        }

        private void LoadWaveFile(string path)
        {
            if (string.IsNullOrWhiteSpace(path))
                return;

            try
            {
                currentFilePath = path;

                waveOut?.Stop();
                waveOut?.Dispose();
                waveOut = null;
                bufferedWaveProvider = null;

                audioSamples = null;
                selectionStart = -1;
                selectionEnd = -1;

                // Check file length and ask about splitting if longer than 20 minutes
                using (var readerDurationCheck = new AudioFileReader(path))
                {
                    double totalSeconds = readerDurationCheck.TotalTime.TotalSeconds;
                    if (totalSeconds > 20 * 60)
                    {
                        DialogResult dr = MessageBox.Show(
                            "Audio file is larger than 20 minutes. Would you like to split it into 20 minute chunks now?",
                            "Large File Warning",
                            MessageBoxButtons.YesNo,
                            MessageBoxIcon.Warning);
                        if (dr == DialogResult.Yes)
                        {
                            SplitAndSaveChunks(path, readerDurationCheck.TotalTime, readerDurationCheck.WaveFormat);
                            return;
                        }
                    }
                }

                using (var reader = new AudioFileReader(path))
                {
                    waveFormat = reader.WaveFormat;
                    sampleRate = waveFormat.SampleRate;

                    long totalFloatSamplesLong = reader.Length / 4;

                    if (totalFloatSamplesLong > int.MaxValue)
                        throw new InvalidOperationException("Audio file too large.");

                    int sampleCount = (int)totalFloatSamplesLong;
                    audioSamples = new float[sampleCount];

                    int offset = 0;
                    int samplesRead;
                    var buffer = new float[1024];

                    reader.Position = 0;
                    while ((samplesRead = reader.Read(buffer, 0, buffer.Length)) > 0)
                    {
                        int copyCount = Math.Min(samplesRead, sampleCount - offset);
                        Array.Copy(buffer, 0, audioSamples, offset, copyCount);
                        offset += copyCount;
                    }
                }

                int totalFrames = audioSamples.Length / waveFormat.Channels;

                viewStartFrame = 0;
                viewFrames = totalFrames;

                btnSave.Enabled = true;

                playStartFrame = 0;
                playEndFrame = totalFrames - 1;

                waveOut = new WaveOutEvent();
                waveOut.PlaybackStopped += WaveOut_PlaybackStopped;

                bufferedWaveProvider = new BufferedWaveProvider(waveFormat)
                {
                    BufferLength = audioSamples.Length * waveFormat.BlockAlign
                };
                bufferedWaveProvider.ClearBuffer();

                byte[] byteBuffer = new byte[audioSamples.Length * 4];
                Buffer.BlockCopy(audioSamples, 0, byteBuffer, 0, byteBuffer.Length);
                bufferedWaveProvider.AddSamples(byteBuffer, 0, byteBuffer.Length);

                waveOut.Init(bufferedWaveProvider);

                waveformPanel.Invalidate();
            }
            catch (Exception ex)
            {
                MessageBox.Show("Failed to load WAV: " + ex.Message);
            }
        }

        private void WaveformPanel_Paint(object sender, PaintEventArgs e)
        {
            e.Graphics.Clear(mainColor);
            if (audioSamples == null || audioSamples.Length == 0)
            {
                using (var brush = new SolidBrush(accentColor))
                    e.Graphics.DrawString("No audio loaded", this.Font, brush, new PointF(10, 10));
                return;
            }

            int w = waveformPanel.ClientSize.Width;
            int h = waveformPanel.ClientSize.Height;

            int totalFrames = audioSamples.Length / waveFormat.Channels;

            using (var pen = new Pen(accentColor))
            {
                if (viewFrames == 0)
                    viewFrames = totalFrames;
                if (viewStartFrame + viewFrames > totalFrames)
                    viewStartFrame = totalFrames - viewFrames;

                if (viewStartFrame < 0) viewStartFrame = 0;
                if (viewFrames <= 0) viewFrames = totalFrames;

                int framesPerPixel = Math.Max(1, viewFrames / w);

                for (int x = 0; x < w; x++)
                {
                    int startFrame = viewStartFrame + x * framesPerPixel;
                    if (startFrame >= totalFrames)
                        break;
                    int endFrame = Math.Min(totalFrames, startFrame + framesPerPixel);

                    float min = 1f;
                    float max = -1f;
                    for (int f = startFrame; f < endFrame; f++)
                    {
                        float sumSample = 0f;
                        for (int c = 0; c < waveFormat.Channels; c++)
                        {
                            float val = audioSamples[f * waveFormat.Channels + c];
                            sumSample += val;
                        }
                        float valAvg = sumSample / waveFormat.Channels;

                        if (valAvg < min) min = valAvg;
                        if (valAvg > max) max = valAvg;
                    }

                    int yMax = (int)((1 - (max + 1) / 2) * h);
                    int yMin = (int)((1 - (min + 1) / 2) * h);

                    e.Graphics.DrawLine(pen, x, yMin, x, yMax);
                }
            }

            // Draw selection rectangle
            if (selectionStart >= 0 && selectionEnd >= 0 && selectionEnd != selectionStart)
            {
                int wFrames = viewFrames;
                int visibleStart = viewStartFrame;
                int x1 = (int)((double)(selectionStart - visibleStart) / wFrames * w);
                int x2 = (int)((double)(selectionEnd - visibleStart) / wFrames * w);

                int rectX = Math.Min(x1, x2);
                int rectW = Math.Abs(x2 - x1);

                if (rectW > 0)
                {
                    using (var selectionBrush = new SolidBrush(Color.FromArgb(100, mainColor)))
                        e.Graphics.FillRectangle(selectionBrush, rectX, 0, rectW, h);

                    using (var pen = new Pen(textColor, 2))
                        e.Graphics.DrawRectangle(pen, rectX, 0, rectW, h - 1);

                    // Draw realtime text anchored centered in the selection rectangle
                    double selectedFrames = Math.Abs(selectionEnd - selectionStart);
                    double selectedSeconds = selectedFrames / (double)sampleRate;
                    string selectionDurationText = $"{selectedSeconds:F2} s selected";

                    using (var font = new Font(this.Font.FontFamily, 10, FontStyle.Bold))
                    using (var brush = new SolidBrush(textColor))
                    {
                        SizeF textSize = e.Graphics.MeasureString(selectionDurationText, font);
                        float textX = rectX + rectW / 2f - textSize.Width / 2f;
                        float textY = h / 2f - textSize.Height / 2f;

                        // Draw text background for better visibility
                        using (var bgBrush = new SolidBrush(Color.FromArgb(160, mainColor)))
                        {
                            RectangleF bgRect = new RectangleF(textX - 4, textY - 2, textSize.Width + 8, textSize.Height + 4);
                            e.Graphics.FillRectangle(bgBrush, bgRect);
                        }

                        e.Graphics.DrawString(selectionDurationText, font, brush, textX, textY);
                    }
                }
            }

            // Draw playback position line
            if (isPlaying && audioSamples != null && waveOut != null)
            {
                int bytesPerSample = sizeof(float);
                int bytesPerFrame = bytesPerSample * waveFormat.Channels;
                long currentFrame = 0;

                try
                {
                    currentFrame = waveOut.GetPosition() / bytesPerFrame + playStartFrame;
                }
                catch
                {
                    currentFrame = 0;
                }

                if (currentFrame > audioSamples.Length / waveFormat.Channels)
                    currentFrame = audioSamples.Length / waveFormat.Channels;

                long segmentLength = playEndFrame - playStartFrame + 1;
                if (segmentLength <= 0) segmentLength = audioSamples.Length / waveFormat.Channels;

                if (currentFrame > playEndFrame)
                    currentFrame = playEndFrame;

                int x = 0;

                if (selectionStart >= 0 && selectionEnd >= 0 && selectionStart != selectionEnd)
                {
                    int wFrames = viewFrames;
                    int visibleStart = viewStartFrame;

                    int sx1 = (int)((double)(selectionStart - visibleStart) / wFrames * w);
                    int sx2 = (int)((double)(selectionEnd - visibleStart) / wFrames * w);

                    int rectX = Math.Min(sx1, sx2);
                    int rectW = Math.Abs(sx2 - sx1);

                    if (segmentLength > 0)
                        x = rectX + (int)((double)(currentFrame - playStartFrame) / segmentLength * rectW);
                    else
                        x = rectX;
                }
                else
                {
                    int wFrames = viewFrames;
                    int visibleStart = viewStartFrame;
                    x = (int)((double)(currentFrame - visibleStart) / wFrames * w);
                }

                if (x >= 0 && x < w)
                {
                    using (var pen = new Pen(textColor, 2))
                        e.Graphics.DrawLine(pen, x, 0, x, h);
                }
            }

            DrawTimeStamps(e.Graphics, w, h);
        }

        private void DrawTimeStamps(Graphics g, int width, int height)
        {
            if (waveFormat == null || audioSamples == null || audioSamples.Length == 0)
                return;

            int totalFrames = audioSamples.Length / waveFormat.Channels;
            if (viewFrames <= 0) return;

            int maxLabels = width / 60;
            if (maxLabels < 2) maxLabels = 2;

            int intervalFrames = viewFrames / maxLabels;
            if (intervalFrames <= 0) intervalFrames = 1;

            using (var brush = new SolidBrush(textColor))
            using (var font = new Font(this.Font.FontFamily, 8))
            using (var pen = new Pen(textColor))
            {
                int yOffset = height - 16;
                int tickHeight = 8;

                for (int i = 0; i <= maxLabels; i++)
                {
                    int framePos = viewStartFrame + i * intervalFrames;
                    if (framePos > totalFrames) framePos = totalFrames;

                    double seconds = (double)framePos / sampleRate;
                    int minutesPart = (int)(seconds / 60);
                    int secondsPart = (int)(seconds % 60);

                    string timeLabel = $"{minutesPart:D2}:{secondsPart:D2}";

                    double positionRatio = (double)(framePos - viewStartFrame) / viewFrames;
                    int x = (int)(positionRatio * width);

                    if (x < 0) x = 0;
                    if (x > width) x = width;

                    g.DrawLine(pen, x, height - tickHeight, x, height);

                    SizeF size = g.MeasureString(timeLabel, font);

                    int textX = x - (int)(size.Width / 2);
                    if (textX < 0) textX = 0;
                    if (textX + size.Width > width) textX = width - (int)size.Width;

                    g.DrawString(timeLabel, font, brush, new PointF(textX, yOffset));
                }
            }
        }

        private void WaveformPanel_MouseDown(object sender, MouseEventArgs e)
        {
            if (audioSamples == null) return;

            int w = waveformPanel.ClientSize.Width;
            int totalFrames = audioSamples.Length / waveFormat.Channels;

            if (e.Button == MouseButtons.Left)
            {
                int frameIndex = viewStartFrame + (int)((double)e.X / w * viewFrames);
                frameIndex = Math.Clamp(frameIndex, 0, totalFrames - 1);

                // Check if clicking near edges for resizing
                if (selectionStart >= 0 && selectionEnd >= 0 && selectionEnd != selectionStart)
                {
                    int selStart = Math.Min(selectionStart, selectionEnd);
                    int selEnd = Math.Max(selectionStart, selectionEnd);

                    int xStart = (int)((double)(selStart - viewStartFrame) / viewFrames * w);
                    int xEnd = (int)((double)(selEnd - viewStartFrame) / viewFrames * w);

                    // Check left edge
                    if (e.X >= xStart - selectionEdgeSensitivity && e.X <= xStart + selectionEdgeSensitivity)
                    {
                        isResizingLeft = true;
                        waveOut.Stop();
                        isPlaying = false;
                        playbackTimer.Stop();
                        return;
                    }
                    // Check right edge
                    if (e.X >= xEnd - selectionEdgeSensitivity && e.X <= xEnd + selectionEdgeSensitivity)
                    {
                        isResizingRight = true;
                        waveOut.Stop();
                        isPlaying = false;
                        playbackTimer.Stop();
                        return;
                    }

                    // Check if clicking inside existing selection to start moving
                    if (e.X >= xStart && e.X <= xEnd)
                    {
                        isMovingSelection = true;
                        lastMouseX = e.X;
                        moveSelectionStartFrameDiff = frameIndex - selStart;

                        // Stop playback when moving
                        if (isPlaying)
                        {
                            waveOut?.Stop();
                            isPlaying = false;
                            playbackTimer.Stop();
                        }

                        return;
                    }

                    // If near left or right edge (cursor is SizeWE), clicking *outside* the selection edges should NOT cancel selection.
                    // Otherwise, clicking outside selection cancels.
                }

                // Determine cursor type at the click point to decide if we should cancel selection or start new
                // We'll only cancel selection if cursor is NOT the "stretch" cursor (SizeWE)
                Cursor currentCursor = waveformPanel.Cursor;
                if (currentCursor != Cursors.SizeWE)
                {
                    // Click outside the selection cancels selection
                    int selStartCheck = Math.Min(selectionStart, selectionEnd);
                    int selEndCheck = Math.Max(selectionStart, selectionEnd);
                    int xStartCheck = (int)((double)(selStartCheck - viewStartFrame) / viewFrames * w);
                    int xEndCheck = (int)((double)(selEndCheck - viewStartFrame) / viewFrames * w);

                    if (e.X < xStartCheck - selectionEdgeSensitivity || e.X > xEndCheck + selectionEdgeSensitivity)
                    {
                        selectionStart = -1;
                        selectionEnd = -1;
                    }
                }

                // If selection cancelled or none exists, start new selection
                if (selectionStart < 0 || selectionEnd < 0 || selectionStart == selectionEnd)
                {
                    isSelecting = true;

                    selectionStart = frameIndex;
                    selectionEnd = frameIndex;
                    waveformPanel.Invalidate();
                }
            }
            else if (e.Button == MouseButtons.Right)
            {
                isPanning = true;
                lastPanMouseX = e.X;
                waveformPanel.Cursor = Cursors.Hand;
            }
        }

        private void WaveformPanel_MouseMove(object sender, MouseEventArgs e)
        {
            if (audioSamples == null) return;

            int w = waveformPanel.ClientSize.Width;
            int totalFrames = audioSamples.Length / waveFormat.Channels;

            if (isResizingLeft && e.Button == MouseButtons.Left)
            {
                int frameIndex = viewStartFrame + (int)((double)e.X / w * viewFrames);
                frameIndex = Math.Clamp(frameIndex, 0, totalFrames - 1);

                int selEnd = selectionEnd;
                if (frameIndex >= selEnd) frameIndex = selEnd - 1;
                if (frameIndex < 0) frameIndex = 0;

                selectionStart = frameIndex;

                waveformPanel.Invalidate();
                return;
            }
            else if (isResizingRight && e.Button == MouseButtons.Left)
            {
                int frameIndex = viewStartFrame + (int)((double)e.X / w * viewFrames);
                frameIndex = Math.Clamp(frameIndex, 0, totalFrames - 1);

                int selStart = selectionStart;
                if (frameIndex <= selStart) frameIndex = selStart + 1;
                if (frameIndex >= totalFrames) frameIndex = totalFrames - 1;

                selectionEnd = frameIndex;

                waveformPanel.Invalidate();
                return;
            }

            if (isMovingSelection && e.Button == MouseButtons.Left)
            {
                // Calculate delta frames based on mouse movement, independent of exact mouse-to-frame mapping
                int pixelDeltaX = e.X - lastMouseX;
                lastMouseX = e.X;

                if (viewFrames <= 0 || w <= 0)
                    return;

                double framesPerPixel = (double)viewFrames / w;
                int frameDelta = (int)(pixelDeltaX * framesPerPixel);

                int selStart = Math.Min(selectionStart, selectionEnd);
                int selEnd = Math.Max(selectionStart, selectionEnd);
                int selectionLength = selEnd - selStart;
                if (selectionLength <= 0) selectionLength = 1;

                int newStart = selStart + frameDelta;
                int newEnd = newStart + selectionLength;

                // Clamp selection within valid frames
                if (newStart < 0)
                {
                    newStart = 0;
                    newEnd = selectionLength;
                }
                if (newEnd > totalFrames)
                {
                    newEnd = totalFrames;
                    newStart = newEnd - selectionLength;
                }

                selectionStart = newStart;
                selectionEnd = newEnd;

                waveformPanel.Invalidate();
                return;
            }

            if (isSelecting && e.Button == MouseButtons.Left)
            {
                int frameIndex = viewStartFrame + (int)((double)e.X / w * viewFrames);
                frameIndex = Math.Clamp(frameIndex, 0, totalFrames - 1);

                selectionEnd = frameIndex;
                waveformPanel.Invalidate();
            }
            else if (isPanning && e.Button == MouseButtons.Right)
            {
                int deltaX = e.X - lastPanMouseX;
                lastPanMouseX = e.X;

                if (viewFrames > 0 && w > 0)
                {
                    double framesPerPixel = (double)viewFrames / w;
                    int deltaFrames = (int)(-deltaX * framesPerPixel);

                    int newViewStartFrame = viewStartFrame + deltaFrames;

                    if (newViewStartFrame < 0)
                        newViewStartFrame = 0;

                    int maxStartFrame = totalFrames - viewFrames;
                    if (maxStartFrame < 0) maxStartFrame = 0;

                    if (newViewStartFrame > maxStartFrame)
                        newViewStartFrame = maxStartFrame;

                    if (newViewStartFrame != viewStartFrame)
                    {
                        viewStartFrame = newViewStartFrame;
                        waveformPanel.Invalidate();
                    }
                }
            }
            else // Update cursor depending on proximity to selection edges
            {
                if (selectionStart >= 0 && selectionEnd >= 0 && selectionEnd != selectionStart)
                {
                    int selStart = Math.Min(selectionStart, selectionEnd);
                    int selEnd = Math.Max(selectionStart, selectionEnd);

                    int xStart = (int)((double)(selStart - viewStartFrame) / viewFrames * w);
                    int xEnd = (int)((double)(selEnd - viewStartFrame) / viewFrames * w);

                    if (e.X >= xStart - selectionEdgeSensitivity && e.X <= xStart + selectionEdgeSensitivity)
                    {
                        waveformPanel.Cursor = Cursors.SizeWE;
                        return;
                    }
                    else if (e.X >= xEnd - selectionEdgeSensitivity && e.X <= xEnd + selectionEdgeSensitivity)
                    {
                        waveformPanel.Cursor = Cursors.SizeWE;
                        return;
                    }
                    else if (e.X > xStart + selectionEdgeSensitivity && e.X < xEnd - selectionEdgeSensitivity)
                    {
                        waveformPanel.Cursor = Cursors.SizeAll;
                        return;
                    }
                }
                waveformPanel.Cursor = Cursors.Default;
            }
        }

        private void WaveformPanel_MouseUp(object sender, MouseEventArgs e)
        {
            if (audioSamples == null) return;

            if (e.Button == MouseButtons.Left)
            {
                if (isSelecting)
                {
                    isSelecting = false;

                    if (Math.Abs(selectionEnd - selectionStart) == 0)
                    {
                        selectionStart = -1;
                        selectionEnd = -1;
                    }
                    waveformPanel.Invalidate();
                }
                else if (isMovingSelection)
                {
                    isMovingSelection = false;
                    waveformPanel.Invalidate();
                }
                else if (isResizingLeft)
                {
                    isResizingLeft = false;
                    waveformPanel.Invalidate();
                }
                else if (isResizingRight)
                {
                    isResizingRight = false;
                    waveformPanel.Invalidate();
                }
            }
            else if (e.Button == MouseButtons.Right)
            {
                isPanning = false;
                waveformPanel.Cursor = Cursors.Default;
            }
        }

        private void DeleteSelection()
        {
            if (audioSamples == null) return;
            if (selectionStart < 0 || selectionEnd < 0) return;

            int start = Math.Min(selectionStart, selectionEnd);
            int end = Math.Max(selectionStart, selectionEnd);
            if (end == start) return;

            int channels = waveFormat.Channels;
            int deletedFrames = end - start;
            int deletedSamples = deletedFrames * channels;

            int oldViewStartFrame = viewStartFrame;
            int oldViewFrames = viewFrames;

            int newTotalFrames = audioSamples.Length / channels - deletedFrames;
            int newLength = newTotalFrames * channels;
            float[] newSamples = new float[newLength];

            Array.Copy(audioSamples, 0, newSamples, 0, start * channels);
            Array.Copy(audioSamples, end * channels, newSamples, start * channels, (audioSamples.Length - end * channels));

            audioSamples = newSamples;

            selectionStart = -1;
            selectionEnd = -1;

            if (isPlaying)
            {
                waveOut?.Stop();
                isPlaying = false;
                playbackTimer.Stop();
            }

            bufferedWaveProvider = new BufferedWaveProvider(waveFormat)
            {
                BufferLength = audioSamples.Length * waveFormat.BlockAlign
            };
            bufferedWaveProvider.ClearBuffer();

            byte[] byteBuffer = new byte[audioSamples.Length * sizeof(float)];
            Buffer.BlockCopy(audioSamples, 0, byteBuffer, 0, byteBuffer.Length);
            bufferedWaveProvider.AddSamples(byteBuffer, 0, byteBuffer.Length);

            waveOut?.Init(bufferedWaveProvider);

            playStartFrame = 0;
            playEndFrame = (audioSamples.Length / channels) - 1;

            if (oldViewStartFrame >= end)
            {
                viewStartFrame = Math.Max(0, oldViewStartFrame - deletedFrames);
                viewFrames = oldViewFrames;
            }
            else if (oldViewStartFrame < end && (oldViewStartFrame + oldViewFrames) > start)
            {
                int newViewFrames = oldViewFrames - deletedFrames;
                if (newViewFrames < minViewFrames) newViewFrames = Math.Min(minViewFrames, audioSamples.Length / channels);
                if (newViewFrames > audioSamples.Length / channels) newViewFrames = audioSamples.Length / channels;

                viewStartFrame = oldViewStartFrame;
                if (viewStartFrame > (audioSamples.Length / channels) - newViewFrames)
                    viewStartFrame = (audioSamples.Length / channels) - newViewFrames;
                if (viewStartFrame < 0) viewStartFrame = 0;

                viewFrames = newViewFrames;
            }
            else
            {
                viewStartFrame = oldViewStartFrame;
                viewFrames = oldViewFrames;
            }

            if (viewFrames > audioSamples.Length / channels)
            {
                viewFrames = audioSamples.Length / channels;
                viewStartFrame = 0;
            }

            waveformPanel.Invalidate();
        }

        private void WaveformPanel_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Delete)
            {
                if (selectionStart >= 0 && selectionEnd >= 0 && selectionEnd != selectionStart)
                {
                    DeleteSelection();
                    e.Handled = true;
                }
            }
        }

        private void BtnSave_Click(object sender, EventArgs e)
        {
            if (audioSamples == null || string.IsNullOrEmpty(currentFilePath)) return;

            try
            {
                waveOut?.Stop();

                using (var writer = new WaveFileWriter(currentFilePath, waveFormat))
                {
                    if (waveFormat.Encoding == WaveFormatEncoding.IeeeFloat)
                    {
                        writer.WriteSamples(audioSamples, 0, audioSamples.Length);
                    }
                    else if (waveFormat.BitsPerSample == 16)
                    {
                        short[] int16Samples = new short[audioSamples.Length];
                        for (int i = 0; i < audioSamples.Length; i++)
                        {
                            float sample = audioSamples[i];
                            sample = Math.Max(-1f, Math.Min(1f, sample));
                            int16Samples[i] = (short)(sample * short.MaxValue);
                        }
                        byte[] bytes = new byte[int16Samples.Length * 2];
                        Buffer.BlockCopy(int16Samples, 0, bytes, 0, bytes.Length);
                        writer.Write(bytes, 0, bytes.Length);
                    }
                    else
                    {
                        MessageBox.Show("Unsupported bit depth: " + waveFormat.BitsPerSample);
                        return;
                    }
                }
                MessageBox.Show("File saved to " + currentFilePath);
            }
            catch (Exception ex)
            {
                MessageBox.Show("Failed to save WAV: " + ex.Message);
            }
            finally
            {
                if (audioSamples != null && audioSamples.Length > 0 && waveFormat != null)
                {
                    waveOut?.Dispose();

                    waveOut = new WaveOutEvent();
                    waveOut.PlaybackStopped += WaveOut_PlaybackStopped;

                    bufferedWaveProvider = new BufferedWaveProvider(waveFormat)
                    {
                        BufferLength = audioSamples.Length * waveFormat.BlockAlign
                    };
                    bufferedWaveProvider.ClearBuffer();

                    byte[] byteBuffer = new byte[audioSamples.Length * 4];
                    Buffer.BlockCopy(audioSamples, 0, byteBuffer, 0, byteBuffer.Length);
                    bufferedWaveProvider.AddSamples(byteBuffer, 0, byteBuffer.Length);

                    waveOut.Init(bufferedWaveProvider);
                }
            }
        }

        private void TogglePlayPause()
        {
            if (audioSamples == null || waveOut == null || waveFormat == null) return;

            int channels = waveFormat.Channels;

            if (!isPlaying)
            {
                if (selectionStart >= 0 && selectionEnd >= 0 && selectionEnd != selectionStart)
                {
                    playStartFrame = Math.Min(selectionStart, selectionEnd);
                    playEndFrame = Math.Max(selectionStart, selectionEnd);
                }
                else
                {
                    playStartFrame = 0;
                    playEndFrame = (audioSamples.Length / channels) - 1;
                }

                waveOut.Stop();

                long totalFrames = playEndFrame - playStartFrame + 1;
                long totalSamples = totalFrames * channels;

                if (playStartFrame < 0 || playEndFrame >= (audioSamples.Length / channels) || totalFrames <= 0)
                {
                    MessageBox.Show("Invalid selection for playback.");
                    return;
                }

                try
                {
                    int bytesPerSample = sizeof(float);
                    int intLengthBytes = (int)(totalSamples * bytesPerSample);
                    int byteOffset = (int)(playStartFrame * channels * bytesPerSample);

                    if (byteOffset < 0 || (byteOffset + intLengthBytes) > audioSamples.Length * bytesPerSample)
                    {
                        MessageBox.Show("Playback selection range is out of audio sample bounds.");
                        return;
                    }

                    bufferedWaveProvider?.ClearBuffer();

                    bufferedWaveProvider = new BufferedWaveProvider(waveFormat)
                    {
                        BufferLength = intLengthBytes
                    };

                    byte[] byteBuffer = new byte[intLengthBytes];
                    Buffer.BlockCopy(audioSamples, byteOffset, byteBuffer, 0, intLengthBytes);
                    bufferedWaveProvider.AddSamples(byteBuffer, 0, intLengthBytes);

                    waveOut.Init(bufferedWaveProvider);
                    waveOut.Play();

                    isPlaying = true;
                    playbackTimer.Start();
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Error occurred during playback start: " + ex.Message);
                    return;
                }
            }
            else
            {
                waveOut.Stop();
                isPlaying = false;
                playbackTimer.Stop();
            }

            waveformPanel.Invalidate();
        }

        private void PlaybackTimer_Tick(object sender, EventArgs e)
        {
            if (!isPlaying) return;

            int bytesPerSample = sizeof(float);
            int channels = waveFormat.Channels;
            int bytesPerFrame = bytesPerSample * channels;

            long currentFrame = 0;

            try
            {
                if (bufferedWaveProvider != null && waveOut != null)
                {
                    long position = waveOut.GetPosition();
                    currentFrame = position / bytesPerFrame + playStartFrame;
                }
            }
            catch
            {
                currentFrame = 0;
            }

            if (currentFrame > playEndFrame)
            {
                waveOut.Stop();
                return;
            }

            waveformPanel.Invalidate();
        }

        private void WaveOut_PlaybackStopped(object sender, StoppedEventArgs e)
        {
            isPlaying = false;
            playbackTimer.Stop();
            waveformPanel.Invalidate();
        }

        private void AudioEditorForm_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Space)
            {
                if (!e.Handled)
                {
                    TogglePlayPause();
                    e.Handled = true;
                }
            }
        }

        private void AudioEditorForm_Load(object sender, EventArgs e)
        {
            if (!string.IsNullOrEmpty(SelectionPath))
            {
                LoadWaveFile(SelectionPath);
            }
            else
            {
                btnSave.Enabled = false;
            }
            BackColor = mainColor;
            btnSave.ForeColor = textColor;
            btnSave.BackColor = mainColor;
            SaveAsCrop.BackColor = mainColor;
            SaveAsCrop.ForeColor = textColor;
        }

        private void AudioEditorForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            waveOut?.Stop();
            waveOut?.Dispose();
            _datasetMaker.Show();
        }

        private void SaveAsCrop_Click(object sender, EventArgs e)
        {
            if (audioSamples == null || string.IsNullOrEmpty(currentFilePath))
            {
                MessageBox.Show("No audio loaded or invalid file path.");
                return;
            }

            if (selectionStart < 0 || selectionEnd < 0 || selectionStart == selectionEnd)
            {
                MessageBox.Show("No selection made.");
                return;
            }

            try
            {
                int channels = waveFormat.Channels;

                int startFrame = Math.Min(selectionStart, selectionEnd);
                int endFrame = Math.Max(selectionStart, selectionEnd);

                int selectedFrames = endFrame - startFrame;
                int selectedSamples = selectedFrames * channels;

                float[] selectedSamplesArray = new float[selectedSamples];
                Array.Copy(audioSamples, startFrame * channels, selectedSamplesArray, 0, selectedSamples);

                WaveFormat selectedFormat = waveFormat;

                string directory = System.IO.Path.GetDirectoryName(currentFilePath);
                string originalFileName = System.IO.Path.GetFileNameWithoutExtension(currentFilePath);
                string extension = System.IO.Path.GetExtension(currentFilePath);

                double startSeconds = (double)startFrame / sampleRate;
                int hours = (int)(startSeconds / 3600);
                int minutes = (int)((startSeconds % 3600) / 60);
                int seconds = (int)(startSeconds % 60);

                string timeStamp = $"{hours:D2}-{minutes:D2}-{seconds:D2}";

                Random rnd = new Random();
                int randomNumber = rnd.Next(1000, 9999);

                string newFileName = $"{originalFileName}_Cropped_{timeStamp}_{randomNumber}{extension}";
                string newFilePath = System.IO.Path.Combine(directory, newFileName);

                using (var writer = new WaveFileWriter(newFilePath, selectedFormat))
                {
                    if (selectedFormat.Encoding == WaveFormatEncoding.IeeeFloat)
                    {
                        writer.WriteSamples(selectedSamplesArray, 0, selectedSamplesArray.Length);
                    }
                    else if (selectedFormat.BitsPerSample == 16)
                    {
                        short[] int16Samples = new short[selectedSamplesArray.Length];
                        for (int i = 0; i < selectedSamplesArray.Length; i++)
                        {
                            float sample = selectedSamplesArray[i];
                            sample = Math.Max(-1f, Math.Min(1f, sample));
                            int16Samples[i] = (short)(sample * short.MaxValue);
                        }
                        byte[] bytes = new byte[int16Samples.Length * 2];
                        Buffer.BlockCopy(int16Samples, 0, bytes, 0, bytes.Length);
                        writer.Write(bytes, 0, bytes.Length);
                    }
                    else
                    {
                        MessageBox.Show("Unsupported bit depth: " + selectedFormat.BitsPerSample);
                        return;
                    }
                }

                MessageBox.Show($"Selection saved as: {newFileName}");
            }
            catch (Exception ex)
            {
                MessageBox.Show("Failed to save cropped selection: " + ex.Message);
                return;
            }

            DeleteSelection();
            _datasetMaker.LoadSpeakers();
        }
    }
}