using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
using FFmpeg.AutoGen;
using SmartAquaViewer.Helper.FFHelper;
using SmartAquaViewer.Model;

namespace SmartAquaViewer.ViewModel
{
    public class FFPlayerViewModel : INotifyPropertyChanged
    {
        public CCTVInfo CCTVInfo { get; set; }

        private ImageSource? _currentFrame;
        public ImageSource? CurrentFrame
        {
            get => _currentFrame;
            set { _currentFrame = value; OnPropertyChanged(); }
        }

        private Visibility _isPlayingVIsibility;
        public Visibility IsPlayingVIsibility
        {
            get => _isPlayingVIsibility;
            set { _isPlayingVIsibility = value; OnPropertyChanged(); }
        }

        //private readonly System.Windows.Controls.Image _img;

        private Thread _videoThread;
        private Thread _renderingThread;
        private CancellationTokenSource _videoCts;
        private CancellationTokenSource _renderCts;

        private readonly object _lockObject = new object();
        private readonly Queue<AVFrame> _frameQueue = new(); // lock 불필요
        private volatile bool _disposed;

        private readonly Dispatcher _ui;

        public FFPlayerViewModel(CCTVInfo cctvInfo)
        {
            CCTVInfo = cctvInfo;
            _ui = Application.Current?.Dispatcher ?? Dispatcher.CurrentDispatcher; // UI 디스패처 보관

            IsPlayingVIsibility = Visibility.Visible;
        }

        public void StartMedia(string rtspURL)
        {
            IsPlayingVIsibility = Visibility.Collapsed;
            CCTVInfo.Status = CCTVStatus.Connected;

            _videoCts = new CancellationTokenSource();
            _renderCts = new CancellationTokenSource();

            _videoThread = new Thread(OpenMedia) { IsBackground = true, Name = "RTSP-Decode" };
            _renderingThread = new Thread(RenderImage) { IsBackground = true, Name = "RTSP-Render" };

            _videoThread.Start();
            _renderingThread.Start();
        }

        private unsafe void OpenMedia()
        {
            try
            {
                using (var sd = new StreamDecoder(CCTVInfo.RtspUrl!))
                using (var vfc = new VideoFrameConverter(sd.FrameSize, sd.PixelFormat, sd.FrameSize, AVPixelFormat.AV_PIX_FMT_BGR24))
                {
                    while (!_videoCts!.IsCancellationRequested)
                    {
                        if (!sd.TryDecodeNextFrame(out var frame))
                        {
                            // 디코드 실패: 너무 바쁘지 않게 살짝 쉼
                            Thread.Sleep(2);
                            continue;
                        }

                        try
                        {
                            AVFrame convertedFrame = vfc.Convert(frame);
                            _frameQueue.Enqueue(convertedFrame);              // 큐 삽입 (길이 제한 적용)
                        }
                        catch (Exception ex)
                        {
                            Debug.WriteLine("Decode/Enqueue error: " + ex.Message);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine("OpenMedia() : " + ex);
            }
        }

        private unsafe void RenderImage()
        {
            try
            {
                while (!_renderCts!.IsCancellationRequested)
                {
                    if (_frameQueue.Count > 0)
                    {
                        AVFrame convertedFrame;
                        lock (_lockObject)
                        {
                            if (_frameQueue.Count > 0)
                            {
                                convertedFrame = _frameQueue.Dequeue();
                            }
                            else
                            {
                                continue;
                            }
                        }
                        try
                        {
                            Bitmap bitmap = new Bitmap(convertedFrame.width, convertedFrame.height, convertedFrame.linesize[0], System.Drawing.Imaging.PixelFormat.Format24bppRgb, (IntPtr)convertedFrame.data[0]);

                            var src = CreateBitmapSource(bitmap);
                            src.Freeze();

                            _ui.BeginInvoke(new Action(() =>
                            {
                                if (_disposed) return;
                                CurrentFrame = src;
                            }), DispatcherPriority.Render);
                        }
                        catch (Exception ex)
                        {
                            Debug.WriteLine("RenderLoop() : " + ex.Message);
                        }
                    }
                }
            }
            catch (OperationCanceledException) { /* 정상 종료 */ }
            finally
            {
                //ClearQueue();
            }
        }

        private static BitmapSource CreateBitmapSource(Bitmap bitmap)
        {
            // GDI 핸들 사용 X. LockBits → BitmapSource.Create 경로만 사용.
            var rect = new System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height);
            var data = bitmap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadOnly, bitmap.PixelFormat);
            try
            {
                // Format24bppRgb ↔ PixelFormats.Bgr24 매칭
                return BitmapSource.Create(
                    data.Width, data.Height, 96, 96,
                    PixelFormats.Bgr24, null,
                    data.Scan0, data.Stride * data.Height, data.Stride);
            }
            finally
            {
                bitmap.UnlockBits(data);
            }
        }

        public void ClosePlayer()
        {
            if (_disposed) return;
            _disposed = true;

            try { _videoCts?.Cancel(); } catch { }
            try { _renderCts?.Cancel(); } catch { }

            try { if (_videoThread?.IsAlive == true) _videoThread.Join(300); } catch { }
            try { if (_renderingThread?.IsAlive == true) _renderingThread.Join(300); } catch { }

            _frameQueue.Clear();

            _videoCts?.Dispose();
            _renderCts?.Dispose();

            CurrentFrame = null;

            IsPlayingVIsibility = Visibility.Visible;
            CCTVInfo.Status = CCTVStatus.Disconnected;
        }

        public event PropertyChangedEventHandler? PropertyChanged;
        private void OnPropertyChanged([CallerMemberName] string? name = null)
            => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
    }
}
