1. Add the ability to click anywhere on the waveform to set that as the playback starting area if nothing is selected, marking it with bar or something. 2. Make it to where if a audio clip longer than 20 mins is uploaded then warn the user about the file being too big and ask them if they want to split it up into 20 min chunks, if yes then do that but delete the originally opened file once it's processed. 3. make left and right arrow keys pan left or right in the waveform if it's zoomed in enough. Return the entire code no commentary ty.

using System;
using System.Drawing;
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 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;

                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;
                    }
                }

                // Otherwise, begin selection
                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)
            {
                int frameIndex = viewStartFrame + (int)((double)e.X / w * viewFrames);
                frameIndex = Math.Clamp(frameIndex, 0, totalFrames - 1);

                int selectionLength = Math.Abs(selectionEnd - selectionStart);
                if (selectionLength == 0) selectionLength = 1;

                int newStart = frameIndex - moveSelectionStartFrameDiff;
                int newEnd = newStart + selectionLength;

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

                selectionStart = newStart;
                selectionEnd = newEnd;

                lastMouseX = e.X;
                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();
        }
    }
}