using Ink_Canvas.Helpers;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;

namespace Ink_Canvas.Controls
{
    /// <summary>
    /// 画布上的多页 PDF：仅显示当前页；翻页与页码由主窗口 PDF 侧栏控制（无 XAML 文件）。
    /// 支持墨迹跟随 PDF 翻页——每页的墨迹独立存储/恢复。
    /// </summary>
    public class PdfEmbeddedView : UserControl
    {
        private readonly Image _pageImage;

        private string _pdfPath;
        private uint _pageCount;
        private uint _currentIndex;
        private bool _compressLargePictures;
        private bool _isPagingBusy;
        private bool _layoutSizeCommitted;

        /// <summary>是否在翻页时保存/恢复墨迹（由调用方在初始化后设置，默认 true）。</summary>
        public bool EnableStrokesPersistence { get; set; } = true;

        /// <summary>按页索引存储的已序列化墨迹数据。</summary>
        private readonly Dictionary<uint, byte[]> _pageStrokes = new Dictionary<uint, byte[]>();

        /// <summary>捕获当前 inkCanvas 墨迹为字节数组（由主窗口注入）。</summary>
        public Func<byte[]> CaptureStrokes { get; set; }

        /// <summary>将字节数组墨迹恢复到 inkCanvas（由主窗口注入）。</summary>
        public Action<byte[]> ApplyStrokes { get; set; }

        /// <summary>清除 inkCanvas 上所有墨迹（由主窗口注入，含 timeMachine 清理）。</summary>
        public Action ClearAllStrokes { get; set; }

        /// <summary>页码或可翻页状态变化（用于更新侧栏）。</summary>
        public event EventHandler PageNavigationStateChanged;

        public PdfEmbeddedView()
        {
            MinWidth = 80;
            MinHeight = 60;

            var grid = new Grid { ClipToBounds = true };
            _pageImage = new Image
            {
                Stretch = Stretch.Uniform,
                HorizontalAlignment = HorizontalAlignment.Center,
                VerticalAlignment = VerticalAlignment.Center
            };
            grid.Children.Add(_pageImage);
            Content = grid;
        }

        /// <summary>
        /// 初始化并显示指定页；由 MainWindow 在 UI 线程创建后调用。
        /// </summary>
        /// <param name="initialPageIndex">从 0 开始的页码，超出范围时夹紧到合法区间。</param>
        public async Task InitializeAsync(string pdfFilePath, uint pageCount, bool compressLargePictures, uint initialPageIndex = 0)
        {
            _pdfPath = pdfFilePath ?? throw new ArgumentNullException(nameof(pdfFilePath));
            _pageCount = pageCount;
            _compressLargePictures = compressLargePictures;
            if (_pageCount == 0)
                _currentIndex = 0;
            else
                _currentIndex = initialPageIndex >= _pageCount ? _pageCount - 1 : initialPageIndex;

            await ShowPageAsync(_currentIndex);
        }

        public string PdfPath => _pdfPath;

        public uint PageCount => _pageCount;

        public uint CurrentPageIndex => _currentIndex;

        public string PageLabelText => _pageCount == 0 ? "" : $"{_currentIndex + 1} / {_pageCount}";

        public bool CanGoPrevious => !_isPagingBusy && _pageCount > 1 && _currentIndex > 0;

        public bool CanGoNext => !_isPagingBusy && _pageCount > 1 && _currentIndex < _pageCount - 1;

        public async Task GoToPreviousPageAsync()
        {
            await GoRelativeAsync(-1);
        }

        public async Task GoToNextPageAsync()
        {
            await GoRelativeAsync(1);
        }

        private void NotifyPageNavigationStateChanged()
        {
            PageNavigationStateChanged?.Invoke(this, EventArgs.Empty);
        }

        private async Task GoRelativeAsync(int delta)
        {
            if (_isPagingBusy || _pageCount <= 1)
                return;
            int next = (int)_currentIndex + delta;
            if (next < 0 || next >= _pageCount)
                return;

            // 翻页前保存当前页墨迹
            if (EnableStrokesPersistence && CaptureStrokes != null)
            {
                byte[] strokes = CaptureStrokes();
                _pageStrokes[_currentIndex] = strokes;
            }

            // 清除所有墨迹
            if (EnableStrokesPersistence && ClearAllStrokes != null)
            {
                ClearAllStrokes();
            }

            _currentIndex = (uint)next;
            await ShowPageAsync(_currentIndex);

            // 翻页后恢复目标页墨迹
            if (EnableStrokesPersistence && ApplyStrokes != null)
            {
                if (_pageStrokes.TryGetValue(_currentIndex, out byte[] savedStrokes) && savedStrokes != null && savedStrokes.Length > 8)
                {
                    ApplyStrokes(savedStrokes);
                }
            }
        }

        private async Task ShowPageAsync(uint pageIndex)
        {
            _isPagingBusy = true;
            NotifyPageNavigationStateChanged();
            try
            {
                BitmapSource raw = await PdfWinRtHelper.RenderPageToBitmapSourceAsync(_pdfPath, pageIndex);
                if (raw == null)
                    return;

                BitmapSource display = ApplyCompressionIfNeeded(raw);
                _pageImage.Source = display;
                if (!_layoutSizeCommitted)
                {
                    bool callerSized = !double.IsNaN(Width) && Width > 0 && !double.IsNaN(Height) && Height > 0;
                    if (!callerSized)
                    {
                        Width = display.PixelWidth;
                        Height = display.PixelHeight;
                    }

                    _layoutSizeCommitted = true;
                }
            }
            finally
            {
                _isPagingBusy = false;
                NotifyPageNavigationStateChanged();
            }
        }

        private BitmapSource ApplyCompressionIfNeeded(BitmapSource rendered)
        {
            int width = rendered.PixelWidth;
            int height = rendered.PixelHeight;
            if (_compressLargePictures && (width > 1920 || height > 1080))
            {
                double scaleX = 1920.0 / width;
                double scaleY = 1080.0 / height;
                double scale = Math.Min(scaleX, scaleY);
                return new TransformedBitmap(rendered, new ScaleTransform(scale, scale));
            }

            return rendered;
        }
    }
}
