using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
using System.Threading.Tasks;
using Emby.Server.Implementations;
using Jellyfin.Server.ServerSetupApp;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Extensions;
using MediaBrowser.Model.IO;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Serilog;
using Serilog.Extensions.Logging;
using ILogger = Microsoft.Extensions.Logging.ILogger;
namespace Jellyfin.Server.Helpers;
/// 
/// A class containing helper methods for server startup.
///  
public static class StartupHelpers
{
    private static readonly string[] _relevantEnvVarPrefixes = { "JELLYFIN_", "DOTNET_", "ASPNETCORE_" };
    /// 
    /// Logs relevant environment variables and information about the host.
    ///  
    /// ();
        foreach (var key in allEnvVars.Keys)
        {
            if (_relevantEnvVarPrefixes.Any(prefix => key.ToString()!.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)))
            {
                relevantEnvVars.Add(key, allEnvVars[key]!);
            }
        }
        logger.LogInformation("Environment Variables: {EnvVars}", relevantEnvVars);
        logger.LogInformation("Arguments: {Args}", commandLineArgs);
        logger.LogInformation("Operating system: {OS}", RuntimeInformation.OSDescription);
        logger.LogInformation("Architecture: {Architecture}", RuntimeInformation.OSArchitecture);
        logger.LogInformation("64-Bit Process: {Is64Bit}", Environment.Is64BitProcess);
        logger.LogInformation("User Interactive: {IsUserInteractive}", Environment.UserInteractive);
        logger.LogInformation("Processor count: {ProcessorCount}", Environment.ProcessorCount);
        logger.LogInformation("Program data path: {ProgramDataPath}", appPaths.ProgramDataPath);
        logger.LogInformation("Log directory path: {LogDirectoryPath}", appPaths.LogDirectoryPath);
        logger.LogInformation("Config directory path: {ConfigurationDirectoryPath}", appPaths.ConfigurationDirectoryPath);
        logger.LogInformation("Cache path: {CachePath}", appPaths.CachePath);
        logger.LogInformation("Temp directory path: {TempDirPath}", appPaths.TempDirectory);
        logger.LogInformation("Web resources path: {WebPath}", appPaths.WebPath);
        logger.LogInformation("Application directory: {ApplicationPath}", appPaths.ProgramSystemPath);
    }
    /// 
    /// Create the data, config and log paths from the variety of inputs(command line args,
    /// environment variables) or decide on what default to use. For Windows it's %AppPath%
    /// for everything else the
    /// XDG approach 
    /// is followed.
    ///  
    /// 
    /// Gets the path for the unix socket Kestrel should bind to.
    ///  
    /// The path for Kestrel to bind to. 
    public static string GetUnixSocketPath(IConfiguration startupConfig, IApplicationPaths appPaths)
    {
        var socketPath = startupConfig.GetUnixSocketPath();
        if (string.IsNullOrEmpty(socketPath))
        {
            const string SocketFile = "jellyfin.sock";
            var xdgRuntimeDir = Environment.GetEnvironmentVariable("XDG_RUNTIME_DIR");
            if (xdgRuntimeDir is null)
            {
                // Fall back to config dir
                socketPath = Path.Join(appPaths.ConfigurationDirectoryPath, SocketFile);
            }
            else
            {
                socketPath = Path.Join(xdgRuntimeDir, SocketFile);
            }
        }
        return socketPath;
    }
    /// 
    /// Sets the unix file permissions for Kestrel's socket file.
    ///  
    /// 
    /// Initialize the logging configuration file using the bundled resource file as a default if it doesn't exist
    /// already.
    ///  
    /// A task representing the creation of the configuration file, or a completed task if the file already exists. 
    public static async Task InitLoggingConfigFile(IApplicationPaths appPaths)
    {
        // Do nothing if the config file already exists
        string configPath = Path.Combine(appPaths.ConfigurationDirectoryPath, Program.LoggingConfigFileDefault);
        if (File.Exists(configPath))
        {
            return;
        }
        // Get a stream of the resource contents
        // NOTE: The .csproj name is used instead of the assembly name in the resource path
        const string ResourcePath = "Jellyfin.Server.Resources.Configuration.logging.json";
        Stream resource = typeof(Program).Assembly.GetManifestResourceStream(ResourcePath)
                          ?? throw new InvalidOperationException($"Invalid resource path: '{ResourcePath}'");
        await using (resource.ConfigureAwait(false))
        {
            Stream dst = new FileStream(configPath, FileMode.CreateNew, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous);
            await using (dst.ConfigureAwait(false))
            {
                // Copy the resource contents to the expected file path for the config file
                await resource.CopyToAsync(dst).ConfigureAwait(false);
            }
        }
    }
    /// 
    /// Initialize Serilog using configuration and fall back to defaults on failure.
    ///  
    /// 
    /// Call static initialization methods for the application.
    ///  
    public static void PerformStaticInitialization()
    {
        // Make sure we have all the code pages we can get
        // Ref: https://docs.microsoft.com/en-us/dotnet/api/system.text.codepagesencodingprovider.instance?view=netcore-3.0#remarks
        Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
    }
}