using Nickvision.Desktop.Application;
using Nickvision.Desktop.Filesystem;
using Nickvision.Parabolic.Shared.Models;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;

namespace Nickvision.Parabolic.Shared.Helpers;

public static class IConfigurationServiceExtensions
{
    extension(IConfigurationService configurationService)
    {
        public bool AllowPreviewUpdates
        {
            get => configurationService.Get("AllowPreviewUpdates", false);

            set => configurationService.Set("AllowPreviewUpdates", value);
        }

        public int AriaMaxConnectionsPerServer
        {
            get => configurationService.Get("AriaMaxConnectionsPerServer", 16);

            set => configurationService.Set("AriaMaxConnectionsPerServer", value);
        }

        public int AriaMinSplitSize
        {
            get => configurationService.Get("AriaMinSplitSize", 20);

            set => configurationService.Set("AriaMinSplitSize", value);
        }

        public Browser CookiesBrowser
        {
            get => configurationService.Get("CookiesBrowser", Browser.None);

            set => configurationService.Set("CookiesBrowser", value);
        }

        public string CookiesPath
        {
            get => configurationService.Get("CookiesPath", string.Empty);

            set => configurationService.Set("CookiesPath", value);
        }

        public bool CropAudioThumbnails
        {
            get => configurationService.Get("CropAudioThumbnails", false);

            set => configurationService.Set("CropAudioThumbnails", value);
        }

        public bool EmbedChapters
        {
            get => configurationService.Get("EmbedChapters", false);

            set => configurationService.Set("EmbedChapters", value);
        }

        public bool EmbedMetadata
        {
            get => configurationService.Get("EmbedMetadata", true);

            set => configurationService.Set("EmbedMetadata", value);
        }

        public bool EmbedSubtitles
        {
            get => configurationService.Get("EmbedSubtitles", true);

            set => configurationService.Set("EmbedSubtitles", value);
        }

        public bool EmbedThumbnails
        {
            get => configurationService.Get("EmbedThumbnails", true);

            set => configurationService.Set("EmbedThumbnails", value);
        }

        public HistoryLength HistoryLength
        {
            get => configurationService.Get("HistoryLength", HistoryLength.OneWeek);

            set => configurationService.Set("HistoryLength", value);
        }

        public bool HistorySortNewest
        {
            get => configurationService.Get("HistorySortNewestFirst", true);

            set => configurationService.Set("HistorySortNewestFirst", value);
        }

        public bool IncludeAutoGeneratedSubtitles
        {
            get => configurationService.Get("IncludeAutoGeneratedSubtitles", true);

            set => configurationService.Set("IncludeAutoGeneratedSubtitles", value);
        }

        public bool IncludeMediaIdInTitle
        {
            get => configurationService.Get("IncludeMediaIdInTitle", true);

            set => configurationService.Set("IncludeMediaIdInTitle", value);
        }

        public bool IncludeSuperResolutions
        {
            get => configurationService.Get("IncludeSuperResolutions", true);

            set => configurationService.Set("IncludeSuperResolutions", value);
        }

        public bool LimitCharacters
        {
            get => configurationService.Get("LimitCharacters", OperatingSystem.IsWindows());

            set => configurationService.Set("LimitCharacters", value);
        }

        public int MaxNumberOfActiveDownloads
        {
            get => configurationService.Get("MaxNumberOfActiveDownloads", 5);

            set => configurationService.Set("MaxNumberOfActiveDownloads", value);
        }

        public bool OverwriteExistingFiles
        {
            get => configurationService.Get("OverwriteExistingFiles", true);

            set => configurationService.Set("OverwriteExistingFiles", value);
        }

        public int PostprocessingThreads
        {
            get => configurationService.Get("PostprocessingThreads", Environment.ProcessorCount);

            set => configurationService.Set("PostprocessingThreads", value);
        }

        public double PreviousAudioBitrate
        {
            get => configurationService.Get("AudioBitrate", double.MaxValue);

            set => configurationService.Set("AudioBitrate", value);
        }

        public Dictionary<MediaFileType, string> PreviousAudioFormatIds
        {
            get => configurationService.Get("AudioFormatIds", new()
            {
                { MediaFileType.Video, Format.BestAudio.Id },
                { MediaFileType.MP4, Format.BestAudio.Id },
                { MediaFileType.MKV, Format.BestAudio.Id },
                { MediaFileType.WEBM, Format.BestAudio.Id },
                { MediaFileType.MOV, Format.BestAudio.Id },
                { MediaFileType.AVI, Format.BestAudio.Id },
                { MediaFileType.Audio, Format.BestAudio.Id },
                { MediaFileType.MP3, Format.BestAudio.Id },
                { MediaFileType.M4A, Format.BestAudio.Id },
                { MediaFileType.OPUS, Format.BestAudio.Id },
                { MediaFileType.FLAC, Format.BestAudio.Id },
                { MediaFileType.WAV, Format.BestAudio.Id },
                { MediaFileType.OGG, Format.BestAudio.Id },
            }, ApplicationJsonContext.Default.DictionaryMediaFileTypeString);

            set => configurationService.Set("AudioFormatIds", value, ApplicationJsonContext.Default.DictionaryMediaFileTypeString);
        }

        public MediaFileType PreviousAudioOnlyFileType
        {
            get => configurationService.Get("AudioOnlyFileType", MediaFileType.MP3);

            set => configurationService.Set("AudioOnlyFileType", value);
        }

        public bool PreviousDownloadImmediatelyAsAudio
        {
            get => configurationService.Get("DownloadImmediatelyAsAudio", false);

            set => configurationService.Set("DownloadImmediatelyAsAudio", value);
        }

        public bool PreviousDownloadImmediatelyAsVideo
        {
            get => configurationService.Get("DownloadImmediatelyAsVideo", false);

            set => configurationService.Set("DownloadImmediatelyAsVideo", value);
        }

        public bool PreviousExportDescription
        {
            get => configurationService.Get("ExportDescription", false);

            set => configurationService.Set("ExportDescription", value);
        }

        public bool PreviousExportM3U
        {
            get => configurationService.Get("ExportM3U", false);

            set => configurationService.Set("ExportM3U", value);
        }

        public MediaFileType PreviousFullFileType
        {
            get => configurationService.Get("FullFileType", MediaFileType.MP4);

            set => configurationService.Set("FullFileType", value);
        }

        public bool PreviousNumberTitles
        {
            get => configurationService.Get("NumberTitles", false);

            set => configurationService.Set("NumberTitles", value);
        }

        public string PreviousPostProcessorArgumentName
        {
            get => configurationService.Get("PostProcessorArgumentName", string.Empty);

            set => configurationService.Set("PostProcessorArgumentName", value);
        }

        public bool PreviousReverseDownloadOrder
        {
            get => configurationService.Get("ReverseDownloadOrder", false);

            set => configurationService.Set("ReverseDownloadOrder", value);
        }

        public string PreviousSaveFolder
        {
            get
            {
                var saveFolder = configurationService.Get("SaveFolder", UserDirectories.Downloads);
                return !Directory.Exists(saveFolder) ? UserDirectories.Downloads : saveFolder;
            }

            set => configurationService.Set("SaveFolder", value);
        }

        public bool PreviousSplitChapters
        {
            get => configurationService.Get("SplitChapters", false);

            set => configurationService.Set("SplitChapters", value);
        }

        public IReadOnlyList<SubtitleLanguage> PreviousSubtitleLanguages
        {
            get => configurationService.Get("SubtitleLanguages", [], ApplicationJsonContext.Default.ListSubtitleLanguage);

            set => configurationService.Set("SubtitleLanguages", value.ToList(), ApplicationJsonContext.Default.ListSubtitleLanguage);
        }

        public Dictionary<MediaFileType, string> PreviousVideoFormatIds
        {
            get => configurationService.Get("VideoFormatIds", new()
            {
                { MediaFileType.Video, Format.BestVideo.Id },
                { MediaFileType.MP4, Format.BestVideo.Id },
                { MediaFileType.MKV, Format.BestVideo.Id },
                { MediaFileType.WEBM, Format.BestVideo.Id },
                { MediaFileType.MOV, Format.BestVideo.Id },
                { MediaFileType.AVI, Format.BestVideo.Id },
                { MediaFileType.Audio, Format.NoneVideo.Id },
                { MediaFileType.MP3, Format.NoneVideo.Id },
                { MediaFileType.M4A, Format.NoneVideo.Id },
                { MediaFileType.OPUS, Format.NoneVideo.Id },
                { MediaFileType.FLAC, Format.NoneVideo.Id },
                { MediaFileType.WAV, Format.NoneVideo.Id },
                { MediaFileType.OGG, Format.NoneVideo.Id },
            }, ApplicationJsonContext.Default.DictionaryMediaFileTypeString);

            set => configurationService.Set("VideoFormatIds", value, ApplicationJsonContext.Default.DictionaryMediaFileTypeString);
        }

        public MediaFileType PreviousVideoOnlyFileType
        {
            get => configurationService.Get("VideoOnlyFileType", MediaFileType.MP4);

            set => configurationService.Set("VideoOnlyFileType", value);
        }

        public VideoResolution PreviousVideoResolution
        {
            get => configurationService.Get("VideoResolution", VideoResolution.Best, ApplicationJsonContext.Default.VideoResolution);

            set => configurationService.Set("VideoResolution", value, ApplicationJsonContext.Default.VideoResolution);
        }

        public List<PostProcessorArgument> PostprocessingArguments
        {
            get => configurationService.Get("PostprocessingArguments", [], ApplicationJsonContext.Default.ListPostProcessorArgument);

            set => configurationService.Set("PostprocessingArguments", value, ApplicationJsonContext.Default.ListPostProcessorArgument);
        }

        public AudioCodec PreferredAudioCodec
        {
            get => configurationService.Get("PreferredAudioCodec", AudioCodec.Any);

            set => configurationService.Set("PreferredAudioCodec", value);
        }

        public FrameRate PreferredFrameRate
        {
            get => configurationService.Get("PreferredFrameRate", FrameRate.Any);

            set => configurationService.Set("PreferredFrameRate", value);
        }

        public SubtitleFormat PreferredSubtitleFormat
        {
            get => configurationService.Get("PreferredSubtitleFormat", SubtitleFormat.Any);

            set => configurationService.Set("PreferredSubtitleFormat", value);
        }

        public VideoCodec PreferredVideoCodec
        {
            get => configurationService.Get("PreferredVideoCodec", VideoCodec.Any);

            set => configurationService.Set("PreferredVideoCodec", value);
        }

        public bool PreventSuspend
        {
            get => configurationService.Get("PreventSuspend", false);

            set => configurationService.Set("PreventSuspend", value);
        }

        public string ProxyUrl
        {
            get => configurationService.Get("ProxyUrl", string.Empty);

            set => configurationService.Set("ProxyUrl", value);
        }

        public bool RemoveSourceData
        {
            get => configurationService.Get("RemoveSourceData", false);

            set => configurationService.Set("RemoveSourceData", value);
        }

        public bool ShowDisclaimerOnStartup
        {
            get => configurationService.Get("ShowDisclaimerOnStartup", true);

            set => configurationService.Set("ShowDisclaimerOnStartup", value);
        }

        public int? SpeedLimit
        {
            get
            {
                var limit = configurationService.Get("SpeedLimit", string.Empty);
                if (int.TryParse(limit, out var result))
                {
                    return result;
                }
                else
                {
                    return null;
                }
            }

            set => configurationService.Set("SpeedLimit", value.HasValue ? value.Value.ToString() : string.Empty);
        }

        public Theme Theme
        {
            get => configurationService.Get("Theme", Theme.System);

            set => configurationService.Set("Theme", value);
        }

        public bool TranslateMetadataAndChapters
        {
            get => configurationService.Get("TranslateMetadataAndChapters", true);

            set => configurationService.Set("TranslateMetadataAndChapters", value);
        }

        public string TranslationLanguage
        {
            get => configurationService.Get("TranslationLanguage", string.Empty);

            set => configurationService.Set("TranslationLanguage", value);
        }

        public bool UseAria
        {
            get => configurationService.Get("UseAria", false);

            set => configurationService.Set("UseAria", value);
        }

        public bool UsePartFiles
        {
            get => configurationService.Get("UsePartFiles", true);

            set => configurationService.Set("UsePartFiles", value);
        }

        public WindowGeometry WindowGeometry
        {
            get => configurationService.Get("WindowGeometry", new WindowGeometry(), ApplicationJsonContext.Default.WindowGeometry);

            set => configurationService.Set("WindowGeometry", value, ApplicationJsonContext.Default.WindowGeometry);
        }

        public bool YouTubeSponsorBlock
        {
            get => configurationService.Get("YouTubeSponsorBlock", false);

            set => configurationService.Set("YouTubeSponsorBlock", value);
        }

        public string YtdlpDiscoveryArgs
        {
            get => configurationService.Get("YtdlpDiscoveryArgs", string.Empty);

            set => configurationService.Set("YtdlpDiscoveryArgs", value);
        }

        public string YtdlpDownloadArgs
        {
            get => configurationService.Get("YtdlpDownloadArgs", string.Empty);

            set => configurationService.Set("YtdlpDownloadArgs", value);
        }

        public async Task<string> ToStringAsync() => JsonSerializer.Serialize(await configurationService.GetAllRawAsync(), ApplicationJsonContext.Default.DictionaryStringString);
    }
}
