using System.Windows.Input;
using VideoConcat.Models;
using MessageBox = System.Windows.MessageBox;
using VideoConcat.Common.Tools;
using System.IO;
using Microsoft.Expression.Drawing.Core;
using FFMpegCore;
using FFMpegCore.Enums;
using static VideoConcat.Models.VideoModel;
using System.Windows.Threading;
using System.Windows;
using System.Diagnostics;
using System.Linq;
// 明确使用 WPF 的 OpenFileDialog，避免与 Windows Forms 冲突
using OpenFileDialog = Microsoft.Win32.OpenFileDialog;
using System.Windows.Forms;

namespace VideoConcat.ViewModels
{
    public class VideoViewModel
    {
        private VideoModel _videoModel;

        public List<ConcatVideo> ConcatVideos { get; set; } = [];

        public VideoModel VideoModel
        {
            get { return _videoModel; }
            set
            {
                _videoModel = value;
            }
        }



        public VideoViewModel()
        {
            VideoModel = new VideoModel
            {
                FolderInfos = [],
                ConcatVideos = [],
                IsJoinType1Selected = true,
                IsJoinType2Selected = false,

                MaxNum = 0,
                CanStart = false,
                IsStart = false,

                BtnOpenFolderCommand = new Command()
                {
                    DoExcue = obj =>
                    {
                        System.Windows.Forms.FolderBrowserDialog folderBrowserDialog = new();
                        if (folderBrowserDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                        {
                            VideoModel.FolderPath = folderBrowserDialog.SelectedPath;
                            LogUtils.Info($"获取视频文件夹,视频路径:{VideoModel.FolderPath}");
                            ListFolder(VideoModel.FolderPath);
                        }
                    }

                },
                BtnChooseAuditImageCommand = new Command()
                {
                    DoExcue = obj =>
                    {
                        // 创建一个 OpenFileDialog 实例（使用 WPF 的 OpenFileDialog）
                        OpenFileDialog openFileDialog = new()
                        {
                            // 设置文件对话框的标题
                            Title = "选择广审图片",
                            // 设置文件筛选器，只允许选择文本文件和图像文件
                            Filter = "图片文件[*.png;*.jpg;*.jpeg;*.bmp]|*.png;*.jpg;*.jpeg;*.bmp",
                        };


                        // 显示文件对话框并获取结果（WPF 返回 bool?）
                        bool? result = openFileDialog.ShowDialog();


                        // 检查用户是否点击了打开按钮
                        if (result == true)
                        {
                            // 获取用户选择的文件路径列表
                            VideoModel.AuditImagePath = openFileDialog.FileName;
                        }
                    }
                },

                BtnStartVideoConcatCommand = new Command()
                {
                    DoExcue = obj =>
                    {
                        Task.Run(action: async () =>
                        {
                            VideoModel.Dispatcher.Invoke(() =>
                            {
                                VideoModel.ConcatVideos.Clear();
                                VideoModel.IsStart = true;
                            });

                            if (Directory.Exists($"{VideoModel.FolderPath}\\output") == false)
                            {
                                Directory.CreateDirectory($"{VideoModel.FolderPath}\\output");
                            }

                            //开始时间
                            DateTime startTime = DateTime.Now;

                            LogUtils.Info("开始合并视频,进行视频拼接组合");
                            List<List<string>> combinations = [];
                            List<string> currentCombination = [];
                            List<List<string>> videoLists = [];


                            VideoModel.FolderInfos.ForEach(folderInfo =>
                            {
                                videoLists.Add(folderInfo.VideoPaths);
                            });
                            string[] _converVideoPath = [];
                            List<List<string>> result = [];
                            Random random = new();
                            if (VideoModel.IsJoinType1Selected)
                            {
                                VideoCombine.GenerateCombinations(videoLists, 0, currentCombination, combinations);

                                // 复制原列表，避免修改原列表
                                List<List<string>> tempList = [.. combinations];
                                for (int i = 0; i < VideoModel.Num && tempList.Count > 0; i++)
                                {
                                    int index = random.Next(tempList.Count);
                                    result.Add(tempList[index]);

                                    _converVideoPath = [.. _converVideoPath, .. tempList[index]];

                                    tempList.RemoveAt(index);
                                }
                            }

                            if (VideoModel.IsJoinType2Selected)
                            {
                                int count = videoLists[0].Count;
                                for (int index = 1; index < count; index++)
                                {
                                    if (videoLists[0].Count != count)
                                    {
                                        WPFDevelopers.Controls.MessageBox.Show("请输入用户名或者密码！");
                                        return;
                                    }
                                }
                                for (int index = 0; index < count; index++)
                                {
                                    List<string> list2 = [];
                                    foreach (List<string> list in videoLists)
                                    {
                                        _converVideoPath=[.. _converVideoPath, list[index]];
                                        list2.Add(list[index]);
                                    }

                                    result.Add(list2);
                                }
                            }

                            SemaphoreSlim semaphore = new(10); // Limit to 3 threads

                            List<Task> _tasks = [];

                            foreach (var _path in _converVideoPath)
                            {
                                await semaphore.WaitAsync(); // Wait when more than 3 threads are running
                                var _task = Task.Run(() =>
                                {
                                    try
                                    {
                                        VideoCombine.mustClearPath.Add(VideoCombine.ConvertVideos(_path));
                                    }
                                    finally
                                    {
                                        semaphore.Release(); // Work is done, signal to semaphore that more work is possible
                                    }
                                });
                                _tasks.Add(_task);
                            }

                            await Task.WhenAll(_tasks).ContinueWith((task) =>
                             {
                                 LogUtils.Info($"转换完成，用时{(DateTime.Now - startTime).TotalSeconds}秒");
                             });

                            LogUtils.Info("开始拼接视频");

                            // 预先创建所有ConcatVideo项，用于显示进度
                            VideoModel.Dispatcher.Invoke(() =>
                            {
                                for (int i = 0; i < result.Count; i++)
                                {
                                    List<string> combination = result[i];
                                    string firstVideoPath = combination[0];
                                    string firstVideoName = Path.GetFileNameWithoutExtension(firstVideoPath);
                                    string _tempFileName = $"{firstVideoName}_{i + 1:D4}.mp4";
                                    string _outPutName = Path.Combine($"{VideoModel.FolderPath}", "output", _tempFileName);

                                    VideoModel.ConcatVideos.Add(new ConcatVideo()
                                    {
                                        Index = i + 1,
                                        FileName = _tempFileName,
                                        FilePath = _outPutName,
                                        Size = "-",
                                        Seconds = 0,
                                        Status = "处理中",
                                        Progress = "0%",
                                    });
                                }
                            });

                            List<Task> taskList = [];
                            semaphore = new(10);

                            for (int combinationIndex = 0; combinationIndex < result.Count; combinationIndex++)
                            {
                                List<string> combination = result[combinationIndex];
                                int currentIndex = combinationIndex + 1; // 序号从1开始，在闭包外计算
                                await semaphore.WaitAsync();
                                var _task = Task.Run(() =>
                                {
                                    // 获取第一个视频的文件名（不含扩展名）
                                    string firstVideoPath = combination[0];
                                    string firstVideoName = Path.GetFileNameWithoutExtension(firstVideoPath);
                                    string _tempFileName = $"{firstVideoName}_{currentIndex:D4}.mp4";
                                    string _outPutName = Path.Combine($"{VideoModel.FolderPath}", "output", _tempFileName); ;

                                    // 更新进度为"准备中"
                                    VideoModel.Dispatcher.Invoke(() =>
                                    {
                                        var videoItem = VideoModel.ConcatVideos.FirstOrDefault(v => v.Index == currentIndex);
                                        if (videoItem != null)
                                        {
                                            videoItem.Progress = "准备中...";
                                            videoItem.Status = "处理中";
                                            // 进度值会在UpdateProgressValue中自动更新
                                        }
                                    });


                                    try
                                    {
                                        var temporaryVideoParts = combination.Select((_videoPath) =>
                                        {
                                            string _tempMd5Name = VideoCombine.GetLargeFileMD5(_videoPath);
                                            //GlobalFFOptions.Current.TemporaryFilesFolder
                                            return Path.Combine(Path.GetTempPath(), $"{_tempMd5Name}{FileExtension.Ts}");
                                        }).ToArray();

                                        bool _isSuccess = false;

                                        // 更新进度为"拼接中"
                                        VideoModel.Dispatcher.Invoke(() =>
                                        {
                                            var videoItem = VideoModel.ConcatVideos.FirstOrDefault(v => v.Index == currentIndex);
                                            if (videoItem != null)
                                            {
                                                videoItem.Progress = "0%";
                                                videoItem.Status = "拼接中";
                                            }
                                        });

                                        try
                                        {
                                            // 计算总时长用于进度计算
                                            double totalDuration = 0;
                                            try
                                            {
                                                foreach (var videoPath in combination)
                                                {
                                                    var analysis = FFProbe.Analyse(videoPath);
                                                    totalDuration += analysis.Duration.TotalSeconds;
                                                }
                                            }
                                            catch
                                            {
                                                totalDuration = 100; // 默认值
                                            }

                                            int currentIndexForProgress = currentIndex;
                                            double processedDuration = 0;
                                            
                                            _isSuccess = FFMpegArguments
                                                .FromConcatInput(temporaryVideoParts)
                                                .OutputToFile(_outPutName, true, options => options
                                                    .CopyChannel()
                                                    .WithBitStreamFilter(Channel.Audio, Filter.Aac_AdtstoAsc)
                                                    .WithFastStart()
                                                    .WithVideoCodec("copy")  // 复制视频流
                                                    .WithAudioCodec("aac")   // 重新编码音频
                                                    .WithAudioSamplingRate(44100) // 强制采样率
                                                    .WithCustomArgument("-movflags +faststart -analyzeduration 100M -probesize 100M")
                                                    )
                                                .NotifyOnOutput((output) =>
                                                {
                                                    // 解析FFmpeg输出获取进度
                                                    // FFmpeg输出格式: time=00:00:05.00 bitrate=...
                                                    if (output.Contains("time="))
                                                    {
                                                        try
                                                        {
                                                            int timeIndex = output.IndexOf("time=");
                                                            if (timeIndex >= 0)
                                                            {
                                                                string timeStr = output.Substring(timeIndex + 5, 11); // time=HH:MM:SS.mm
                                                                if (TimeSpan.TryParse(timeStr, out TimeSpan currentTime))
                                                                {
                                                                    processedDuration = currentTime.TotalSeconds;
                                                                    int progressPercent = totalDuration > 0 
                                                                        ? (int)((processedDuration / totalDuration) * 100) 
                                                                        : 0;
                                                                    progressPercent = Math.Min(100, Math.Max(0, progressPercent));
                                                                    
                                                                    VideoModel.Dispatcher.Invoke(() =>
                                                                    {
                                                                        var videoItem = VideoModel.ConcatVideos.FirstOrDefault(v => v.Index == currentIndexForProgress);
                                                                        if (videoItem != null)
                                                                        {
                                                                            videoItem.Progress = $"{progressPercent}%";
                                                                        }
                                                                    });
                                                                }
                                                            }
                                                        }
                                                        catch
                                                        {
                                                            // 忽略解析错误
                                                        }
                                                    }
                                                })
                                                .ProcessSynchronously();
                                        }
                                        catch (Exception ex)
                                        {
                                            _isSuccess = false;
                                            LogUtils.Error("拼接视频失败", ex);
                                        }

                                        //bool _isSuccess = FFMpeg.Join(_outPutName, [.. combination]);

                                        // 更新拼接结果
                                        VideoModel.Dispatcher.Invoke(() =>
                                        {
                                            var videoItem = VideoModel.ConcatVideos.FirstOrDefault(v => v.Index == currentIndex);
                                            if (videoItem != null && File.Exists(_outPutName))
                                            {
                                                try
                                                {
                                                    IMediaAnalysis _mediaInfo = FFProbe.Analyse(_outPutName);
                                                    FileInfo fileInfo = new(_outPutName);

                                                    videoItem.FilePath = _outPutName;
                                                    videoItem.Size = $"{fileInfo.Length / 1024 / 1024}MB";
                                                    videoItem.Seconds = ((int)_mediaInfo.Duration.TotalSeconds);
                                                    videoItem.Status = _isSuccess ? "拼接成功" : "拼接失败";
                                                    videoItem.Progress = _isSuccess ? "100%" : "失败";
                                                }
                                                catch (Exception ex)
                                                {
                                                    videoItem.Status = "拼接失败";
                                                    videoItem.Progress = "失败";
                                                    LogUtils.Error($"分析视频信息失败：{_outPutName}", ex);
                                                }
                                            }
                                            else if (videoItem != null)
                                            {
                                                videoItem.Status = "拼接失败";
                                                videoItem.Progress = "失败";
                                            }
                                        });


                                        if (_isSuccess && VideoModel.AuditImagePath != "")
                                        {
                                            // 使用 FFMpegCore 执行添加图片到视频的操作
                                            try
                                            {
                                                // 配置 FFmpeg 二进制文件位置（如果 FFmpeg 不在系统路径中）
                                                // GlobalFFOptions.Configure(new FFOptions { BinaryFolder = "path/to/ffmpeg/bin" });

                                                // 使用相同的命名规则，添加 _img 后缀表示带水印
                                                string firstVideoPathName = combination[0];
                                                string firstVideoNameHas = Path.GetFileNameWithoutExtension(firstVideoPathName);
                                                string _outPutNameImg = Path.Combine($"{VideoModel.FolderPath}", "output", $"{firstVideoNameHas}_{currentIndex:D4}_img.mp4");

                                                string _customArg = "-filter_complex \"[0:v][1:v] overlay=0:H-h\" ";
                                                // 使用 FFMpegArguments 构建命令
                                                bool _isCoverSuccess = FFMpegArguments
                                                   .FromFileInput(_outPutName)
                                                   .AddFileInput(VideoModel.AuditImagePath)
                                                   .OutputToFile(
                                                    _outPutNameImg,
                                                   true,
                                                   options => options
                                                            .WithCustomArgument(_customArg)// 或显式指定编码器参数
                                                        .WithCustomArgument("-movflags +faststart") // 确保 moov atom 正确写入
                                                   )
                                                   .ProcessSynchronously();


                                                LogUtils.Info($"图片已成功添加到视频中，输出文件：{_outPutName}");
                                            }
                                            catch (Exception ex)
                                            {
                                                LogUtils.Error($"图片添加到视频中失败", ex);
                                            }
                                        }


                                        LogUtils.Info($"当前视频-[${_outPutName}]： {string.Join("；", combination)}    合并成功");
                                    }
                                    catch (Exception ex)
                                    {
                                        LogUtils.Error($"视频[${_outPutName}]：{string.Join("；", combination)}   合并失败", ex);
                                    }
                                    finally
                                    {
                                        semaphore.Release();
                                    }

                                });
                                taskList.Add(_task);
                            }


                            await Task.WhenAll(taskList).ContinueWith((s) =>
                            {
                                //结束时间
                                DateTime endTime = DateTime.Now;
                                double elapsedSeconds = (endTime - startTime).TotalSeconds;
                                
                                // 统计成功和失败的数量
                                int successCount = 0;
                                int failCount = 0;
                                string outputDir = "";
                                
                                VideoModel.Dispatcher.Invoke(() =>
                                {
                                    successCount = VideoModel.ConcatVideos.Count(v => v.Status == "拼接成功");
                                    failCount = VideoModel.ConcatVideos.Count(v => v.Status == "拼接失败");
                                    
                                    if (VideoModel.ConcatVideos.Count > 0)
                                    {
                                        var firstVideo = VideoModel.ConcatVideos.FirstOrDefault(v => !string.IsNullOrEmpty(v.FilePath));
                                        if (firstVideo != null && !string.IsNullOrEmpty(firstVideo.FilePath))
                                        {
                                            outputDir = Path.GetDirectoryName(firstVideo.FilePath) ?? "";
                                        }
                                    }
                                });
                                
                                LogUtils.Info($"所有视频拼接完成，用时{elapsedSeconds:F2}秒，成功{successCount}个，失败{failCount}个");

                                VideoModel.IsStart = false;
                                VideoCombine.Cleanup(VideoCombine.mustClearPath);
                                
                                // 构建提示信息
                                string message = $"所有视频拼接完成！\n\n";
                                message += $"成功：{successCount} 个\n";
                                if (failCount > 0)
                                {
                                    message += $"失败：{failCount} 个\n";
                                }
                                message += $"用时：{elapsedSeconds:F2} 秒\n";
                                if (!string.IsNullOrEmpty(outputDir))
                                {
                                    message += $"\n输出目录：\n{outputDir}";
                                }
                                
                                VideoModel.Dispatcher.Invoke(() =>
                                {
                                    MessageBox.Show(message, "拼接完成", MessageBoxButton.OK, MessageBoxImage.Information);
                                });
                                
                                VideoCombine.mustClearPath = [];
                            });
                        });
                    }
                }
            };
        }

        private void ListFolder(string path)
        {
            DirectoryInfo dir = new(path);
            try
            {
                DirectoryInfo dirD = dir as DirectoryInfo;
                DirectoryInfo[] folders = [.. dirD.GetDirectories().OrderBy(d => d.Name)];

                VideoModel.FolderInfos.Clear();
                //获取文件夹下所有视频文件
                foreach (DirectoryInfo Folder in folders)
                {
                    if (Folder.Name != "output")
                    {
                        string[] files = Directory.GetFiles(Folder.FullName, "*.mp4");
                        LogUtils.Info($"{Folder.Name}下有{files.Length}个视频文件");

                        VideoModel.FolderInfos.Add(new VideoModel.FolderInfo { DirectoryInfo = Folder, Num = files.Length, VideoPaths = new List<string>(files) });
                    }
                }
                VideoModel.UpdateSum();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
                return;
            }
        }
    }

    class Command : ICommand
    {
        public event EventHandler? CanExecuteChanged;

        public bool CanExecute(object? parameter) => true;

        public void Execute(object? parameter)
        {
            DoExcue?.Invoke(parameter);
        }

        public Action<Object?>? DoExcue { get; set; }
    }
}
