using EchoHub.Client.Services;
using Terminal.Gui.App;
using Terminal.Gui.Drawing;
using Terminal.Gui.ViewBase;
using Terminal.Gui.Views;
using Attribute = Terminal.Gui.Drawing.Attribute;

namespace EchoHub.Client.UI.Dialogs;

public sealed class AudioPlayerDialog
{
    // Block characters for wave animation (increasing height)
    private static readonly string[] WaveBlocks = ["\u2581", "\u2582", "\u2583", "\u2584", "\u2585", "\u2586", "\u2587", "\u2588"];
    private const int WaveBarCount = 24;
    private const int AnimationIntervalMs = 150;

    private static readonly Attribute WaveActiveAttr = new(new Color(180, 100, 255), Color.None);
    private static readonly Attribute WaveIdleAttr = new(new Color(80, 50, 120), Color.None);
    private static readonly Attribute FileNameAttr = new(new Color(180, 100, 255), Color.None);
    private static readonly Attribute StatusPlayingAttr = new(new Color(0, 200, 0), Color.None);
    private static readonly Attribute StatusPausedAttr = new(new Color(220, 180, 0), Color.None);
    private static readonly Attribute StatusStoppedAttr = new(new Color(160, 160, 160), Color.None);

    public static void Show(IApplication app, AudioPlaybackService audioService, string filePath, string fileName)
    {
        var dialog = new Dialog { Title = "Audio Player", Width = 52, Height = 12 };

        // ── File name ──
        var fileLabel = new Label
        {
            Text = $"\u266a {TruncateFileName(fileName, 44)}",
            X = 2,
            Y = 1,
            Width = Dim.Fill(2)
        };

        // ── Wave visualization ──
        var waveLabel = new Label
        {
            X = 2,
            Y = 3,
            Width = Dim.Fill(2),
            Height = 1
        };

        // ── Status label ──
        var statusLabel = new Label
        {
            Text = "Stopped",
            X = 2,
            Y = 5,
            Width = 20
        };

        // ── Volume controls ──
        var volumeHeaderLabel = new Label
        {
            Text = "Volume:",
            X = 2,
            Y = 7
        };

        byte currentVolume = 50;

        var volDownButton = new Button
        {
            Text = "-",
            X = 10,
            Y = 7,
            Width = 1,
            Height = 1,
            NoDecorations = true,
            NoPadding = true,
            ShadowStyle = ShadowStyle.None
        };

        var volumeBar = new ProgressBar
        {
            X = 12,
            Y = 7,
            Width = 22,
            Height = 1,
            Fraction = currentVolume / 100f,
            ProgressBarStyle = ProgressBarStyle.Continuous
        };

        var volUpButton = new Button
        {
            Text = "+",
            X = 35,
            Y = 7,
            Width = 1,
            Height = 1,
            NoDecorations = true,
            NoPadding = true,
            ShadowStyle = ShadowStyle.None
        };

        var volumePercentLabel = new Label
        {
            Text = $"{currentVolume}%",
            X = 37,
            Y = 7,
            Width = 5
        };

        // ── Playback controls ──
        var playButton = new Button
        {
            Text = "\u25b6 Play",
            X = 2,
            Y = 9,
            IsDefault = true,
            ShadowStyle = ShadowStyle.None
        };

        var stopButton = new Button
        {
            Text = "\u25a0 Stop",
            X = Pos.Right(playButton) + 1,
            Y = 9,
            ShadowStyle = ShadowStyle.None
        };

        var closeButton = new Button
        {
            Text = "Close",
            X = Pos.Right(stopButton) + 1,
            Y = 9,
            ShadowStyle = ShadowStyle.None
        };

        // ── Animation state ──
        var animationOffset = 0;
        var random = new Random();
        // Pre-generate a repeating wave pattern
        var wavePattern = new int[WaveBarCount + 8];
        for (int i = 0; i < wavePattern.Length; i++)
            wavePattern[i] = random.Next(0, WaveBlocks.Length);

        Timer? animationTimer = null;
        var isDisposed = false;
        var isBusy = false;

        // ── Helper functions ──
        void UpdateWave(bool isActive)
        {
            if (isDisposed) return;

            var bars = new string[WaveBarCount];
            for (int i = 0; i < WaveBarCount; i++)
            {
                if (isActive)
                {
                    var idx = wavePattern[(i + animationOffset) % wavePattern.Length];
                    bars[i] = WaveBlocks[idx];
                }
                else
                {
                    bars[i] = WaveBlocks[1]; // low idle bars
                }
            }
            waveLabel.Text = string.Join(" ", bars);
        }

        void UpdateStatus()
        {
            if (isDisposed) return;

            if (audioService.IsPlaying && !audioService.IsPaused)
            {
                statusLabel.Text = "Playing";
                playButton.Text = "\u23f8 Pause";
            }
            else if (audioService.IsPaused)
            {
                statusLabel.Text = "Paused";
                playButton.Text = "\u25b6 Resume";
            }
            else
            {
                statusLabel.Text = "Stopped";
                playButton.Text = "\u25b6 Play";
            }
        }

        void StartAnimation()
        {
            animationTimer?.Dispose();
            animationTimer = new Timer(_ =>
            {
                if (isDisposed) return;
                animationOffset++;
                // Shuffle a few bars each tick for organic movement
                var idx = random.Next(0, wavePattern.Length);
                wavePattern[idx] = random.Next(0, WaveBlocks.Length);

                app.Invoke(() =>
                {
                    if (isDisposed) return;
                    UpdateWave(true);
                });
            }, null, 0, AnimationIntervalMs);
        }

        void StopAnimation()
        {
            animationTimer?.Dispose();
            animationTimer = null;
            if (!isDisposed)
                UpdateWave(false);
        }

        async Task UpdateVolume(byte newVolume)
        {
            currentVolume = Math.Clamp(newVolume, (byte)0, (byte)100);
            await audioService.SetVolumeAsync(currentVolume);
            if (!isDisposed)
            {
                volumeBar.Fraction = currentVolume / 100f;
                volumePercentLabel.Text = $"{currentVolume}%";
            }
        }

        // ── Custom drawing for colored elements ──
        fileLabel.DrawingContent += (s, e) =>
        {
            var normalAttr = fileLabel.GetAttributeForRole(VisualRole.Normal);
            var resolvedAttr = FileNameAttr.Background == Color.None
                ? FileNameAttr with { Background = normalAttr.Background }
                : FileNameAttr;
            fileLabel.SetAttribute(resolvedAttr);
            fileLabel.Move(0, 0);
            var text = fileLabel.Text ?? "";
            foreach (var g in Terminal.Gui.Drawing.GraphemeHelper.GetGraphemes(text))
                fileLabel.AddStr(g);
            // Fill remaining width
            var width = fileLabel.Viewport.Width;
            var textCols = Terminal.Gui.Text.StringExtensions.GetColumns(text);
            for (int i = textCols; i < width; i++)
                fileLabel.AddStr(" ");
            e.Cancel = true;
        };

        waveLabel.DrawingContent += (s, e) =>
        {
            var normalAttr = waveLabel.GetAttributeForRole(VisualRole.Normal);
            var attr = (audioService.IsPlaying && !audioService.IsPaused) ? WaveActiveAttr : WaveIdleAttr;
            var resolvedAttr = attr.Background == Color.None
                ? attr with { Background = normalAttr.Background }
                : attr;
            waveLabel.SetAttribute(resolvedAttr);
            waveLabel.Move(0, 0);
            var text = waveLabel.Text ?? "";
            foreach (var g in Terminal.Gui.Drawing.GraphemeHelper.GetGraphemes(text))
                waveLabel.AddStr(g);
            var width = waveLabel.Viewport.Width;
            var textCols = Terminal.Gui.Text.StringExtensions.GetColumns(text);
            for (int i = textCols; i < width; i++)
                waveLabel.AddStr(" ");
            e.Cancel = true;
        };

        statusLabel.DrawingContent += (s, e) =>
        {
            var normalAttr = statusLabel.GetAttributeForRole(VisualRole.Normal);
            Attribute attr;
            if (audioService.IsPlaying && !audioService.IsPaused)
                attr = StatusPlayingAttr;
            else if (audioService.IsPaused)
                attr = StatusPausedAttr;
            else
                attr = StatusStoppedAttr;

            var resolvedAttr = attr.Background == Color.None
                ? attr with { Background = normalAttr.Background }
                : attr;
            statusLabel.SetAttribute(resolvedAttr);
            statusLabel.Move(0, 0);
            var text = statusLabel.Text ?? "";
            foreach (var g in Terminal.Gui.Drawing.GraphemeHelper.GetGraphemes(text))
                statusLabel.AddStr(g);
            var width = statusLabel.Viewport.Width;
            var textCols = Terminal.Gui.Text.StringExtensions.GetColumns(text);
            for (int i = textCols; i < width; i++)
                statusLabel.AddStr(" ");
            e.Cancel = true;
        };

        // ── Event handlers ──
        playButton.Accepting += (s, e) =>
        {
            e.Handled = true;
            if (isBusy) return;
            isBusy = true;
            Task.Run(async () =>
            {
                if (audioService.IsPaused)
                {
                    await audioService.ResumeAsync();
                    app.Invoke(() =>
                    {
                        UpdateStatus();
                        StartAnimation();
                        isBusy = false;
                    });
                }
                else if (audioService.IsPlaying)
                {
                    await audioService.PauseAsync();
                    app.Invoke(() =>
                    {
                        UpdateStatus();
                        StopAnimation();
                        isBusy = false;
                    });
                }
                else
                {
                    await audioService.SetVolumeAsync(currentVolume);
                    await audioService.PlayAsync(filePath);
                    app.Invoke(() =>
                    {
                        UpdateStatus();
                        StartAnimation();
                        isBusy = false;
                    });
                }
            });
        };

        stopButton.Accepting += (s, e) =>
        {
            e.Handled = true;
            if (isBusy) return;
            isBusy = true;
            Task.Run(async () =>
            {
                await audioService.StopAsync();
                app.Invoke(() =>
                {
                    UpdateStatus();
                    StopAnimation();
                    isBusy = false;
                });
            });
        };

        closeButton.Accepting += (s, e) =>
        {
            e.Handled = true;
            isDisposed = true;
            animationTimer?.Dispose();
            _ = audioService.StopAsync(); // fire-and-forget
            app.RequestStop();
        };

        volDownButton.Accepting += (s, e) =>
        {
            e.Handled = true;
            if (isBusy) return;
            isBusy = true;
            var newVol = (byte)Math.Max(0, currentVolume - 10);
            Task.Run(async () =>
            {
                await UpdateVolume(newVol);
                app.Invoke(() =>
                {
                    volumeBar.SetNeedsDraw();
                    volumePercentLabel.SetNeedsDraw();
                    isBusy = false;
                });
            });
        };

        volUpButton.Accepting += (s, e) =>
        {
            e.Handled = true;
            if (isBusy) return;
            isBusy = true;
            var newVol = (byte)Math.Min(100, currentVolume + 10);
            Task.Run(async () =>
            {
                await UpdateVolume(newVol);
                app.Invoke(() =>
                {
                    volumeBar.SetNeedsDraw();
                    volumePercentLabel.SetNeedsDraw();
                    isBusy = false;
                });
            });
        };

        // Handle playback finishing naturally
        EventHandler? finishedHandler = null;
        finishedHandler = (s, e) =>
        {
            app.Invoke(() =>
            {
                if (isDisposed) return;
                UpdateStatus();
                StopAnimation();
            });
        };
        audioService.PlaybackFinished += finishedHandler;

        // ── Initial state ──
        UpdateWave(false);
        UpdateStatus();

        dialog.Add(fileLabel, waveLabel, statusLabel,
            volumeHeaderLabel, volDownButton, volumeBar, volumePercentLabel, volUpButton,
            playButton, stopButton, closeButton);

        playButton.SetFocus();
        app.Run(dialog);

        // Cleanup
        isDisposed = true;
        animationTimer?.Dispose();
        audioService.PlaybackFinished -= finishedHandler;
    }

    private static string TruncateFileName(string name, int maxLen)
    {
        if (name.Length <= maxLen)
            return name;

        var ext = Path.GetExtension(name);
        var stem = Path.GetFileNameWithoutExtension(name);
        var available = maxLen - ext.Length - 3; // 3 for "..."
        if (available < 1)
            return name[..maxLen];

        return stem[..available] + "..." + ext;
    }
}
