using DirectShowLib;
using System;
using System.Runtime.InteropServices;

namespace DualScreenDemo.Services
{
    public class MediaService : Video
    {
        public IGraphBuilder graphBuilder;
        private IMediaControl mediaControl;
        private IBaseFilter videoRenderer;
        private IBaseFilter lavSplitter;
        private IBaseFilter lavVideoDecoder;
        private IBaseFilter lavAudioDecoder;
        private IPin outputPin;
        private IBaseFilter audioRenderer;
        private IVideoWindow videoWindow;


        public int Run()
        {
            if (mediaControl != null)
                return mediaControl.Run();
            else
                return 0;
        }
        public int Stop()
        {
            if (mediaControl != null)
                return mediaControl.Stop();
            else
                return 0;

        }
        public int Pause()
        {
            if (mediaControl != null)
                return mediaControl.Pause();
            else
                return 0;
        }
        public void VideoPlayerFormClosing()
        {
            if (videoWindow != null)
            {
                videoWindow.put_Visible(OABool.False);
                videoWindow.put_Owner(IntPtr.Zero);
                Marshal.ReleaseComObject(videoWindow);
                videoWindow = null;
            }
        }
        public void StopAndReleaseResources()
        {
            if (mediaControl != null)
            {
                mediaControl.Stop();
                SafeRelease(ref mediaControl);
            }
            SafeRelease(ref videoWindow);
            SafeRelease(ref videoRenderer);
            SafeRelease(ref lavAudioDecoder);
            SafeRelease(ref outputPin);
            SafeRelease(ref lavVideoDecoder);
            SafeRelease(ref lavSplitter);
            SafeRelease(ref graphBuilder);
            
        }
        public bool isAtEnd()
        {
            bool isAtEnd = false;
            if (mediaControl == null) { return false; }
            IMediaSeeking mediaSeeking = graphBuilder as IMediaSeeking;
            if (mediaSeeking != null)
            {
                long currentPosition;
                long duration;
                if (mediaSeeking.GetCurrentPosition(out currentPosition) >= 0 &&
                    mediaSeeking.GetDuration(out duration) >= 0)
                {
                    double currentSeconds = currentPosition / 10000000.0;
                    double durationSeconds = duration / 10000000.0;

                    // 添加更严格的结束条件判断
                    isAtEnd = durationSeconds > 0 && currentSeconds > 0 &&
                                 Math.Abs(currentSeconds - durationSeconds) < 0.1; // 确保真的到了结尾
                    //Console.WriteLine($"檢測到歌曲 - 當前位置: {currentSeconds:F2}秒, 總時長: {durationSeconds:F2}秒");
                    if (isAtEnd)
                    { 
                        Console.WriteLine($"檢測到歌曲 -結束: {currentSeconds:F2}秒, 總時長: {durationSeconds:F2}秒");
                    }
                }
            }
            return isAtEnd;
        }
        public void RenderMediaFile(string filePath, nint Handle, int Width, int Height)
        {
            StopAndReleaseResources();
            if (videoWindow != null) videoWindow.put_Visible(OABool.False);
            int hr = 0;
            graphBuilder = (IGraphBuilder)new FilterGraph();
            if (graphBuilder == null)
            {
                Console.WriteLine("Failed to create FilterGraph");
                throw new Exception("Failed to create FilterGraph");
            }
            try
            {
                lavSplitter = AddFilterByClsid(graphBuilder, "LAV Splitter", Clsid.LAVSplitter);
                lavVideoDecoder = AddFilterByClsid(graphBuilder, "LAV Video Decoder", Clsid.LAVVideoDecoder);
                lavAudioDecoder = AddFilterByClsid(graphBuilder, "LAV Audio Decoder", Clsid.LAVAudioDecoder);
                outputPin = FindPin(lavAudioDecoder, "Output");
                videoRenderer = AddFilterByClsid(graphBuilder, "Secondary Video Renderer", Clsid.VideoRenderer);
                if (videoRenderer == null)
                {
                    Console.WriteLine("Failed to initialize Secondary Video Renderer.");
                    return;
                }
                hr = graphBuilder.AddFilter(videoRenderer, "Secondary Video Renderer");
                DsError.ThrowExceptionForHR(hr);
                var clsidAudioRenderer = new Guid("79376820-07D0-11CF-A24D-0020AFD79767");  // CLSID for DirectSound Renderer
                audioRenderer = (IBaseFilter)Activator.CreateInstance(Type.GetTypeFromCLSID(clsidAudioRenderer));
                hr = graphBuilder.AddFilter(audioRenderer, "Default DirectSound Device");
                DsError.ThrowExceptionForHR(hr);

                mediaControl = (IMediaControl)graphBuilder;
                if (mediaControl == null)
                {
                    Console.WriteLine("Failed to get Media Control");
                    return;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error initializing graph builder with second monitor: " + ex.Message);
            }
            hr = graphBuilder.RenderFile(filePath, null);
            if (hr == 0)
            {
                Console.WriteLine("Secondary File rendered successfully.");
                SetAudioTrackTo(1);
            }
            else
            {
                Console.WriteLine("Failed to render secondary file.");
            }
            // 绑定视频窗口到副屏幕
            videoWindow = videoRenderer as IVideoWindow;
            if (videoWindow != null)
            {
                videoWindow.put_Owner(Handle); // 副屏幕窗口句柄
                videoWindow.put_WindowStyle(WindowStyle.Child | WindowStyle.ClipChildren | WindowStyle.ClipSiblings);
                videoWindow.SetWindowPosition(0, 0, Width, Height);
                videoWindow.put_Visible(OABool.True); // 显示窗口
            }
        }
        public void SetVolume(int volume)
        {
            if (audioRenderer != null)
            {
                IBasicAudio basicAudio = audioRenderer as IBasicAudio;
                if (basicAudio != null)
                {
                    basicAudio.put_Volume(volume);
                }
            }
        }
        public int GetVolume()
        {
            if (audioRenderer != null)
            {
                IBasicAudio basicAudio = audioRenderer as IBasicAudio;
                if (basicAudio != null)
                {
                    int volume;
                    basicAudio.get_Volume(out volume);
                    return volume;
                }
            }
            return -10000;
        }
        private bool isVocalRemoved = false;
        public bool ToggleVocalRemoval()
        {
            try
            {
                IAMStreamSelect streamSelect = lavSplitter as IAMStreamSelect;

                if (streamSelect != null)
                {
                    int trackCount;
                    if (streamSelect.Count(out trackCount) == 0 && trackCount > 0)
                    {
                        int currentTrackIndex = -1;
                        int audioTrack1 = -1;
                        int audioTrack2 = -1;

                        for (int i = 0; i < trackCount; i++)
                        {
                            // 獲取音軌信息
                            AMMediaType mediaType;
                            AMStreamSelectInfoFlags flags;
                            int lcid, dwGroup;
                            string name;
                            object pObject, pUnk;

                            streamSelect.Info(i, out mediaType, out flags, out lcid, out dwGroup, out name, out pObject, out pUnk);

                            if (mediaType.majorType == MediaType.Audio)
                            {
                                if (audioTrack1 == -1)
                                {
                                    audioTrack1 = i;
                                }
                                else if (audioTrack2 == -1)
                                {
                                    audioTrack2 = i;
                                }

                                if ((flags & AMStreamSelectInfoFlags.Enabled) != 0)
                                {
                                    currentTrackIndex = i;
                                }
                            }

                            DsUtils.FreeAMMediaType(mediaType);
                        }

                        // 切換音軌
                        if (currentTrackIndex == audioTrack1 && audioTrack2 != -1)
                        {
                            streamSelect.Enable(audioTrack2, AMStreamSelectEnableFlags.Enable);
                            isVocalRemoved = true;
                        }
                        else if (currentTrackIndex == audioTrack2 && audioTrack1 != -1)
                        {
                            streamSelect.Enable(audioTrack1, AMStreamSelectEnableFlags.Enable);
                            isVocalRemoved = false;
                        }


                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            return isVocalRemoved;
        }
        public void SetAudioTrackTo(int trackIndex)
        {
            try
            {
                IAMStreamSelect streamSelect = lavSplitter as IAMStreamSelect;

                if (streamSelect != null)
                {
                    int trackCount;
                    if (streamSelect.Count(out trackCount) == 0 && trackCount > 0)
                    {
                        int audioTrackIndex = -1;

                        for (int i = 0; i < trackCount; i++)
                        {
                            AMMediaType mediaType;
                            AMStreamSelectInfoFlags flags;
                            int lcid, dwGroup;
                            string name;
                            object pObject, pUnk;

                            streamSelect.Info(i, out mediaType, out flags, out lcid, out dwGroup, out name, out pObject, out pUnk);

                            if (mediaType.majorType == MediaType.Audio)
                            {
                                audioTrackIndex++;
                                if (audioTrackIndex == trackIndex)
                                {
                                    streamSelect.Enable(i, AMStreamSelectEnableFlags.Enable);
                                }
                                else
                                {
                                    streamSelect.Enable(i, AMStreamSelectEnableFlags.DisableAll);
                                }
                            }

                            DsUtils.FreeAMMediaType(mediaType);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
    }
}