using ManageLiteAV;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;

namespace JianGongYun.TRTC.Components
{
    public class TXLiteAVVideoView : Canvas, IDisposable
    {
        private bool mOccupy = false;     // view 是否已被占用
        private bool mLocalView = false;  // 是否为本地画面
        private bool mPause = false;
        private bool mFirstFrame = false;

        private string mUserId;
        private TRTCVideoStreamType mStreamType;
        private TRTCVideoFillMode mRenderMode = TRTCVideoFillMode.TRTCVideoFillMode_Fit;  // 0：填充，1：适应

        private volatile FrameBufferInfo mArgbFrame = new FrameBufferInfo();  // 帧缓存

        // 位图缓存，防止GC频繁
        private WriteableBitmap mWriteableBitmap;
        private Int32Rect mInt32Rect;
        private Pen mPen;

        public TXLiteAVVideoView()
        {
            mPen = new Pen { Brush = Brushes.DarkGray, Thickness = 1 };
        }

        /// <summary>
        /// 设置 View 绑定参数
        /// </summary>
        /// <param name="userId">需要渲染画面的 userId，如果是本地画面，则传空字符串。</param>
        /// <param name="type">渲染类型</param>
        /// <param name="engine">TRTCCloud 实例，用户注册视频数据回调。</param>
        /// <param name="local">渲染本地画面，SDK 返回的 userId 为""</param>
        /// <returns>true：绑定成功，false：绑定失败</returns>
        public bool RegEngine(string userId, TRTCVideoStreamType type, ITRTCCloud engine, bool local = false)
        {
            if (mOccupy) return false;
            mLocalView = local;
            mUserId = userId;
            mStreamType = type;
            int count = TXLiteAVVideoViewManager.GetInstance().Count;
            if (engine != null)
            {
                if (count == 0)
                {
                    engine.setLocalVideoRenderCallback(TRTCVideoPixelFormat.TRTCVideoPixelFormat_BGRA32,
                        TRTCVideoBufferType.TRTCVideoBufferType_Buffer, TXLiteAVVideoViewManager.GetInstance());
                }
                if (!mLocalView)
                {
                    engine.setRemoteVideoRenderCallback(userId, TRTCVideoPixelFormat.TRTCVideoPixelFormat_BGRA32,
                        TRTCVideoBufferType.TRTCVideoBufferType_Buffer, TXLiteAVVideoViewManager.GetInstance());
                }
            }
            if (mLocalView)
                TXLiteAVVideoViewManager.GetInstance().AddView("", type, this);
            else
                TXLiteAVVideoViewManager.GetInstance().AddView(userId, type, this);
            lock (mArgbFrame)
                ReleaseBuffer(mArgbFrame);
            mOccupy = true;
            this.InvalidateVisual();
            return true;
        }

        /// <summary>
        /// 移除 View 绑定参数
        /// </summary>
        /// <param name="engine">TRTCCloud 实例，用户注册视频数据回调。</param>
        public void RemoveEngine(ITRTCCloud engine)
        {
            if (mLocalView)
                TXLiteAVVideoViewManager.GetInstance().RemoveView("", mStreamType, this);
            else
                TXLiteAVVideoViewManager.GetInstance().RemoveView(mUserId, mStreamType, this);
            int count = TXLiteAVVideoViewManager.GetInstance().Count;
            if (engine != null)
            {
                if (count == 0)
                {
                    engine.setLocalVideoRenderCallback(TRTCVideoPixelFormat.TRTCVideoPixelFormat_Unknown,
                        TRTCVideoBufferType.TRTCVideoBufferType_Unknown, null);
                }
                if (!mLocalView && !TXLiteAVVideoViewManager.GetInstance().HasUserId(mUserId))
                {
                    engine.setRemoteVideoRenderCallback(mUserId, TRTCVideoPixelFormat.TRTCVideoPixelFormat_Unknown,
                        TRTCVideoBufferType.TRTCVideoBufferType_Unknown, null);
                }
            }
            lock (mArgbFrame)
                ReleaseBuffer(mArgbFrame);
            mUserId = "";
            mOccupy = false;
            mLocalView = false;
            mFirstFrame = false;
            mRenderMode = TRTCVideoFillMode.TRTCVideoFillMode_Fit;
            this.InvalidateVisual();
        }

        /// <summary>
        /// 设置 View 的渲染模式
        /// </summary>
        /// <param name="mode">渲染模式</param>
        public void SetRenderMode(TRTCVideoFillMode mode)
        {
            mRenderMode = mode;
        }

        /// <summary>
        /// 判断 View 是否被占用
        /// </summary>
        /// <returns>true：当前 View 已被占用，false：当前 View 未被占用</returns>
        public bool IsViewOccupy()
        {
            return mOccupy;
        }

        /// <summary>
        /// 暂停渲染，显示默认图片
        /// </summary>
        /// <param name="pause">是否暂停</param>
        public void SetPause(bool pause)
        {
            if (mPause != pause)
            {
                mPause = pause;
                if (mPause)
                {
                    this.Background = new SolidColorBrush(Color.FromArgb(0xFF, 0x20, 0x20, 0x20));
                }
                else
                {
                    this.Background = new SolidColorBrush(Color.FromArgb(0xFF, 0x00, 0x00, 0x00));
                    // 避免刷新最后一帧数据
                    lock (mArgbFrame)
                        ReleaseBuffer(mArgbFrame);
                }
                this.InvalidateVisual();
            }
        }

        /// <summary>
        /// 清除所有映射信息
        /// </summary>
        public static void RemoveAllRegEngine()
        {
            TXLiteAVVideoViewManager.GetInstance().RemoveAllView();
        }

        public bool AppendVideoFrame(byte[] data, int width, int height, TRTCVideoPixelFormat videoFormat, TRTCVideoRotation rotation)
        {
            if (!mFirstFrame)
                mFirstFrame = true;
            if (mPause)
                return false;
            if (data == null || data.Length <= 0)
                return false;
            // data 数据有误
            if (videoFormat == TRTCVideoPixelFormat.TRTCVideoPixelFormat_BGRA32 && width * height * 4 != data.Length)
                return false;
            // 暂时不支持其他 YUV 类型
            if (videoFormat == TRTCVideoPixelFormat.TRTCVideoPixelFormat_I420 && width * height * 3 / 2 != data.Length)
                return false;

            // 目前只实现了 BGRA32 的数据类型，如需其他类型请重写，并设置回调的数据类型
            if (videoFormat == TRTCVideoPixelFormat.TRTCVideoPixelFormat_BGRA32)
            {
                lock (mArgbFrame)
                {
                    if (mArgbFrame.data == null || mArgbFrame.width != width || mArgbFrame.height != height)
                    {
                        ReleaseBuffer(mArgbFrame);
                        mArgbFrame.width = width;
                        mArgbFrame.height = height;
                        mArgbFrame.data = new byte[data.Length];
                    }
                    Buffer.BlockCopy(data, 0, mArgbFrame.data, 0, (int)data.Length);
                    mArgbFrame.newFrame = true;
                    mArgbFrame.rotation = rotation;
                }
            }

            // 回到主线程刷新当前画面
            this.Dispatcher.Invoke(new Action(() =>
            {
                this.InvalidateVisual();
            }));

            return true;
        }

        protected override void OnRender(DrawingContext dc)
        {
            bool needDrawFrame = true;
            if (mPause)
                needDrawFrame = false;
            if (mArgbFrame.data == null)
                needDrawFrame = false;
            if (!needDrawFrame)
            {
                return;
            }

            lock (mArgbFrame)
            {
                if (mArgbFrame.data == null)
                    return;
                if (mRenderMode == TRTCVideoFillMode.TRTCVideoFillMode_Fill)
                {
                    RenderFillMode(dc, mArgbFrame.data, mArgbFrame.width, mArgbFrame.height, (int)mArgbFrame.rotation * 90);
                }
                else if (mRenderMode == TRTCVideoFillMode.TRTCVideoFillMode_Fit)
                {
                    RenderFitMode(dc, mArgbFrame.data, mArgbFrame.width, mArgbFrame.height, (int)mArgbFrame.rotation * 90);
                }
            }
        }

        /// <summary>
        /// 渲染回调int width, int height, int rotation,WriteableBitmap image
        /// </summary>
        public event Action<int, int, int, WriteableBitmap> OnRenderVideoFrameHandler;

        private void RenderFillMode(DrawingContext dc, byte[] data, int width, int height, int rotation)
        {
            int viewWidth = (int)this.ActualWidth, viewHeight = (int)this.ActualHeight;
            PixelFormat pixelFormat = PixelFormats.Pbgra32;
            int bytesPerPixel = (pixelFormat.BitsPerPixel + 7) / 8;
            int stride = bytesPerPixel * width;
            if (mWriteableBitmap == null || mWriteableBitmap.PixelWidth != width || mWriteableBitmap.PixelHeight != height)
            {
                mWriteableBitmap = new WriteableBitmap(width, height, 96, 96, pixelFormat, null);
                mInt32Rect = new Int32Rect(0, 0, width, height);
            }
            mWriteableBitmap.Lock();
            Marshal.Copy(data, 0, mWriteableBitmap.BackBuffer, data.Length);
            mWriteableBitmap.AddDirtyRect(mInt32Rect);
            mWriteableBitmap.Unlock();

            //var tt = ConvertWriteableBitmapToBitmapImage(mWriteableBitmap);
            //OpenCvSharp.Mat result = OpenCvSharp.Extensions.BitmapConverter.ToMat(tt);
            //tt.Dispose();
            //result.Create(mWriteableBitmap.PixelHeight, mWriteableBitmap.PixelWidth, OpenCvSharp.MatType.CV_8UC4, 4);
            //mWriteableBitmap.CopyPixels(Int32Rect.Empty, result.Data, data.Length, 4);
            //LiveClassroom.bbb.Enqueue(result);
            //result.ImWrite($"d:\\{DateTime.Now.ToString("yyyyMMddHHmmssfff")}.png");
            //var a = ConvertWriteableBitmapToBitmapImage(mWriteableBitmap);
            //a.Save($"d:\\{DateTime.Now.ToString("yyyyMMddHHmmssfff")}.png");
            OnRenderVideoFrameHandler?.Invoke(width, height, rotation, mWriteableBitmap);

            ImageBrush brush = new ImageBrush(mWriteableBitmap);
            if (rotation > 0)
            {
                Matrix transform = Matrix.Identity;
                double scale = (double)viewWidth / (double)viewHeight;
                if (rotation == 90 || rotation == 270)
                    transform.ScaleAt(scale, scale, 0.5, 0.5);
                transform.RotateAt(rotation, 0.5, 0.5);
                brush.RelativeTransform = new MatrixTransform(transform);
            }
            brush.Stretch = Stretch.UniformToFill;
            Rect rect = new Rect(0, 0, viewWidth, viewHeight);
            dc.DrawRectangle(brush, mPen, rect);
        }



        private void RenderFitMode(DrawingContext dc, byte[] data, int width, int height, int rotation)
        {
            int viewWidth = (int)this.ActualWidth, viewHeight = (int)this.ActualHeight;
            PixelFormat pixelFormat = PixelFormats.Pbgra32;
            int bytesPerPixel = (pixelFormat.BitsPerPixel + 7) / 8;
            int stride = bytesPerPixel * width;
            if (mWriteableBitmap == null || mWriteableBitmap.PixelWidth != width || mWriteableBitmap.PixelHeight != height)
            {
                mWriteableBitmap = new WriteableBitmap(width, height, 96, 96, pixelFormat, null);
                //Mat result = new Mat();
                //result.Create(mWriteableBitmap.PixelHeight, mWriteableBitmap.PixelWidth, MatType.CV_8U, 4);
                //mWriteableBitmap.CopyPixels(Int32Rect.Empty, result.Data, (int)result.Step() * result.Rows, (int)result.Step());
                mInt32Rect = new Int32Rect(0, 0, width, height);
            }
            mWriteableBitmap.Lock();
            Marshal.Copy(data, 0, mWriteableBitmap.BackBuffer, data.Length);
            mWriteableBitmap.AddDirtyRect(mInt32Rect);
            mWriteableBitmap.Unlock();

            OnRenderVideoFrameHandler?.Invoke(width, height, rotation, mWriteableBitmap);

            ImageBrush brush = new ImageBrush(mWriteableBitmap);
            if (rotation > 0)
            {
                Matrix transform = Matrix.Identity;
                double scale = (double)viewHeight / (double)viewWidth;
                if (rotation == 90 || rotation == 270)
                    transform.ScaleAt(1, scale, 0.5, 0.5);
                transform.RotateAt(rotation, 0.5, 0.5);
                brush.RelativeTransform = new MatrixTransform(transform);
            }
            brush.Stretch = Stretch.Uniform;
            Rect rect = new Rect(0, 0, viewWidth, viewHeight);
            dc.DrawRectangle(brush, mPen, rect);
        }

        private void ReleaseBuffer(FrameBufferInfo info)
        {
            if (info.data != null)
                info.data = null;
            info.width = 0;
            info.height = 0;
            info.newFrame = false;
            info.rotation = TRTCVideoRotation.TRTCVideoRotation0;
        }

        #region Dispose
        private bool disposed = false;

        public void Dispose()
        {
            this.Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (disposed) return;
            if (disposing)
            {
                ReleaseBuffer(mArgbFrame);
                mWriteableBitmap = null;
            }
            disposed = true;
        }

        ~TXLiteAVVideoView()
        {
            this.Dispose(false);
        }
        #endregion
    }

    public class TXLiteAVVideoViewManager : ITRTCVideoRenderCallback
    {
        private volatile Dictionary<string, TXLiteAVVideoView> mMapViews;

        public static TXLiteAVVideoViewManager sInstance;

        private static Object mLocker = new Object();

        public static TXLiteAVVideoViewManager GetInstance()
        {
            if (sInstance == null)
            {
                lock (mLocker)
                {
                    if (sInstance == null)
                        sInstance = new TXLiteAVVideoViewManager();
                }
            }
            return sInstance;
        }

        private TXLiteAVVideoViewManager()
        {
            mMapViews = new Dictionary<string, TXLiteAVVideoView>();
        }

        private string GetKey(string userId, TRTCVideoStreamType type)
        {
            return String.Format("{0}_{1}", userId, type);
        }

        // 主要用于判断当前 user 是否还有存在流画面，存在则不移除监听。
        public bool HasUserId(string userId)
        {
            bool exit = false;
            lock (mMapViews)
            {
                exit = mMapViews.ContainsKey(GetKey(userId, TRTCVideoStreamType.TRTCVideoStreamTypeBig)) ||
                    mMapViews.ContainsKey(GetKey(userId, TRTCVideoStreamType.TRTCVideoStreamTypeSub));
            }
            return exit;
        }

        public void AddView(string userId, TRTCVideoStreamType type, TXLiteAVVideoView view)
        {
            lock (mMapViews)
            {
                bool find = false;
                foreach (var item in mMapViews)
                {
                    if (item.Key.Equals(GetKey(userId, type)))
                    {
                        find = true;
                        break;
                    }
                }
                if (!find)
                {
                    mMapViews.Add(GetKey(userId, type), view);
                }
            }
        }

        public void RemoveView(string userId, TRTCVideoStreamType type, TXLiteAVVideoView view)
        {
            lock (mMapViews)
            {
                foreach (var item in mMapViews.ToList())
                {
                    if (item.Key.Equals(GetKey(userId, type)))
                    {
                        if (item.Value != null)
                        {
                            item.Value.Dispose();
                        }
                        mMapViews.Remove(item.Key);
                        break;
                    }
                }
            }
        }

        public void RemoveAllView()
        {
            lock (mMapViews)
                mMapViews.Clear();
        }

        public int Count
        {
            get
            {
                lock (mMapViews)
                    return mMapViews.Count;
            }
        }

        //public event Action<string, TRTCVideoStreamType, TRTCVideoFrame> OnRenderVideoFrameHandler;
        /// <summary>
        /// 自定义渲染回调，只能存在一个回调
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="streamType"></param>
        /// <param name="frame"></param>
        public void onRenderVideoFrame(string userId, TRTCVideoStreamType streamType, TRTCVideoFrame frame)
        {
            //OnRenderVideoFrameHandler?.Invoke(userId, streamType, frame);
            // 大小视频是占一个视频位，底层支持动态切换。
            if (streamType == TRTCVideoStreamType.TRTCVideoStreamTypeSmall)
                streamType = TRTCVideoStreamType.TRTCVideoStreamTypeBig;
            TXLiteAVVideoView view = null;
            lock (mMapViews)
            {
                foreach (var item in mMapViews)
                {
                    if (item.Key.Equals(GetKey(userId, streamType)) && item.Value != null)
                    {
                        view = item.Value;
                        break;
                    }
                }
            }
            if (view != null)
                view.AppendVideoFrame(frame.data, (int)frame.width, (int)frame.height, frame.videoFormat, frame.rotation);
        }
    }

    class FrameBufferInfo
    {
        public byte[] data { get; set; }

        public int width { get; set; }

        public int height { get; set; }

        public bool newFrame { get; set; }

        public TRTCVideoRotation rotation { get; set; }

        public FrameBufferInfo()
        {
            rotation = TRTCVideoRotation.TRTCVideoRotation0;
            newFrame = false;
            width = 0;
            height = 0;
            data = null;
        }
    }
}
