using System;
using System.IO;
using System.IO.Abstractions;
using System.Reflection;
using System.Text.RegularExpressions;
using Quadarax.Foundation.Core.Value.Extensions;


namespace Quadarax.Foundation.Core.IO
{
    public static class FileUtils
    {
        private const string CS_CFG_VAR = "LocalAppData";


        private static Regex? _removeInvalidChars;

        public static string SanitizedFileName(IFileSystem fileSystemAbstraction, string fileName, string replacement = "_")
        {
            if (fileSystemAbstraction == null)
                throw new ArgumentNullException(nameof(fileSystemAbstraction));
            if (string.IsNullOrEmpty(fileName))
                throw new ArgumentNullException(nameof(fileName));

            _removeInvalidChars ??= new Regex($"[{Regex.Escape(new string(fileSystemAbstraction.Path.GetInvalidFileNameChars()))}]",
                RegexOptions.Singleline | RegexOptions.Compiled | RegexOptions.CultureInvariant);

            return _removeInvalidChars.Replace(fileName, replacement);
        }



        public static void TestWriteTempFile(IFileSystem fileSystemAbstraction, string directory)
        {

            if (fileSystemAbstraction == null)
                throw new ArgumentNullException(nameof(fileSystemAbstraction));

            var fileName = fileSystemAbstraction.Path.GetRandomFileName();
            var fullFileName = directory.EnsurePathBackslash() + fileName;
            using (var sw = fileSystemAbstraction.File.CreateText(fullFileName))
            {
                sw.Write('T');
                sw.Flush();
            }
            if (fileSystemAbstraction.File.Exists(fullFileName))
                fileSystemAbstraction.File.Delete(fullFileName);
        }

        public static string EnsurePathEndsWithDirSeparator(IFileSystem fileSystemAbstraction, string directoryPath)
        {
            if (fileSystemAbstraction == null && !string.IsNullOrEmpty(directoryPath))
                throw new ArgumentNullException(nameof(fileSystemAbstraction));

            var sepChar = '\\';
            if (fileSystemAbstraction != null)
                sepChar = fileSystemAbstraction.Path.DirectorySeparatorChar;

            if (string.IsNullOrEmpty(directoryPath))
                return directoryPath;
            directoryPath = directoryPath.Trim();
            if (directoryPath.EndsWith(sepChar))
                return directoryPath;
            return directoryPath + sepChar;
        }
        public static string EnsurePathNotEndsWithDirSeparator(IFileSystem fileSystemAbstraction, string directoryPath)
        {
            if (fileSystemAbstraction == null && !string.IsNullOrEmpty(directoryPath))
                throw new ArgumentNullException(nameof(fileSystemAbstraction));

            if (string.IsNullOrEmpty(directoryPath))
                return directoryPath;
            directoryPath = directoryPath.Trim();
            if (fileSystemAbstraction != null && !directoryPath.EndsWith(GetDirSepChar(fileSystemAbstraction)))
                return directoryPath;
            return directoryPath.RemoveLast();
        }


        public static string? GetConfigBasePath(IFileSystem fileSystemAbstraction)
        {
#if LINUX
            return $"{fileSystemAbstraction.Path.DirectorySeparatorChar}etc";
#else
#if DEBUG
            var localAppDir = fileSystemAbstraction.Directory.GetCurrentDirectory();
#else
            var localAppDir = Environment.GetEnvironmentVariable(CS_CFG_VAR);
#endif
            if (string.IsNullOrEmpty(localAppDir))
                return Assembly.GetEntryAssembly()?.Location;
            return EnsurePathNotEndsWithDirSeparator(fileSystemAbstraction, localAppDir.EnsurePathNonBackslash());
#endif

        }
        public static string GetConfigPath(IFileSystem fileSystemAbstraction)
        {
            return EnsurePathNotEndsWithDirSeparator(fileSystemAbstraction, (GetConfigBasePath(fileSystemAbstraction) + fileSystemAbstraction.Path.DirectorySeparatorChar + Assembly.GetEntryAssembly().GetName().Name));
        }

        public static string GetLogsPath(IFileSystem fileSystemAbstraction)
        {
            return EnsurePathNotEndsWithDirSeparator(fileSystemAbstraction,(GetLogBasePath(fileSystemAbstraction) + Path.DirectorySeparatorChar + Assembly.GetEntryAssembly()?.GetName().Name));
        }


        public static string GetLogBasePath(IFileSystem fileSystemAbstraction)
        {
#if LINUX
            return $"{fileSystemAbstraction.Path.DirectorySeparatorChar}var{fileSystemAbstraction.Path.DirectorySeparatorChar}logs";
#else
            return GetConfigBasePath(fileSystemAbstraction);
#endif
        }

        private static char GetDirSepChar(IFileSystem fileSystemAbstraction)
        {
            var sepChar = fileSystemAbstraction.Path.DirectorySeparatorChar;
            return sepChar;
        }
    }
}
