using System;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;

namespace Электронная_Фармация.Classes
{
    /// <summary>
    /// File logger for API/auth/network debugging.
    /// Logs are written to %LocalAppData%\ЭльФиСА\...\Logs\api-debug-YYYY-MM-DD.log.
    /// </summary>
    public static class AppDebugLog
    {
        private static readonly object Sync = new object();
        private const int MaxBodyLength = 8000;
        private const string DisableEnvVar = "ELF_API_DEBUG";
        private const string DisableMarkerFile = "api-debug.off";

        public static bool IsEnabled
        {
            get
            {
                var env = Environment.GetEnvironmentVariable(DisableEnvVar);
                if (string.Equals(env, "0", StringComparison.OrdinalIgnoreCase) ||
                    string.Equals(env, "false", StringComparison.OrdinalIgnoreCase))
                {
                    return false;
                }

                var markerPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, DisableMarkerFile);
                return !File.Exists(markerPath);
            }
        }

        public static string LogDirectory => AppConfig.LogsDirectory;

        public static string CurrentLogFilePath =>
            Path.Combine(LogDirectory, $"api-debug-{DateTime.Now:yyyy-MM-dd}.log");

        public static void Info(string category, string message)
        {
            Write("INFO", category, message, null);
        }

        public static void Warning(string category, string message)
        {
            Write("WARN", category, message, null);
        }

        public static void Error(string category, string message, Exception exception = null)
        {
            Write("ERROR", category, message, exception);
        }

        public static void ApiRequest(string method, string url, string requestBody = null, string extra = null)
        {
            var message = new StringBuilder();
            message.Append(method).Append(" ").Append(url);
            if (!string.IsNullOrWhiteSpace(extra))
            {
                message.Append(" | ").Append(extra);
            }

            if (!string.IsNullOrWhiteSpace(requestBody))
            {
                message.Append(" | body=").Append(Truncate(SanitizeJson(requestBody)));
            }

            Write("REQ", "Api", message.ToString(), null);
        }

        public static void ApiResponse(string method, string url, int statusCode, long elapsedMs, string responseBody = null)
        {
            var message = new StringBuilder();
            message.Append(method).Append(" ").Append(url);
            message.Append(" -> HTTP ").Append(statusCode);
            message.Append(" (").Append(elapsedMs).Append(" ms)");

            if (!string.IsNullOrWhiteSpace(responseBody))
            {
                message.Append(" | body=").Append(Truncate(SanitizeJson(responseBody)));
            }

            Write(statusCode >= 400 ? "RESP-ERR" : "RESP", "Api", message.ToString(), null);
        }

        public static void ApiFailure(string method, string url, long elapsedMs, Exception exception)
        {
            var message = $"{method} {url} failed after {elapsedMs} ms: {exception?.Message}";
            Write("FAIL", "Api", message, exception);
        }

        /// <summary>
        /// Логирует ошибку HTTP-ответа API (4xx/5xx) с телом ответа.
        /// </summary>
        public static void ApiHttpError(
            string method,
            string url,
            int statusCode,
            string responseBody,
            string context = null)
        {
            var message = new StringBuilder();
            message.Append(method).Append(" ").Append(url);
            message.Append(" -> HTTP ").Append(statusCode);
            if (!string.IsNullOrWhiteSpace(context))
            {
                message.Append(" | ").Append(context);
            }

            if (!string.IsNullOrWhiteSpace(responseBody))
            {
                message.Append(" | body=").Append(Truncate(SanitizeJson(responseBody)));
            }

            Write("HTTP-ERR", "Api", message.ToString(), null);
        }

        public static string MaskToken(string token)
        {
            if (string.IsNullOrWhiteSpace(token))
            {
                return "(empty)";
            }

            if (token.Length <= 8)
            {
                return "***";
            }

            return token.Substring(0, 4) + "..." + token.Substring(token.Length - 4);
        }

        public static string SanitizeJson(string json)
        {
            if (string.IsNullOrWhiteSpace(json))
            {
                return string.Empty;
            }

            var sanitized = Regex.Replace(
                json,
                @"""password""\s*:\s*""[^""]*""",
                @"""password"":""***""",
                RegexOptions.IgnoreCase);

            sanitized = Regex.Replace(
                sanitized,
                @"""token""\s*:\s*""([^""]*)""",
                m => @"""token"":""" + MaskToken(m.Groups[1].Value) + @"""",
                RegexOptions.IgnoreCase);

            return sanitized;
        }

        public static string FormatException(Exception exception)
        {
            if (exception == null)
            {
                return string.Empty;
            }

            var sb = new StringBuilder();
            var current = exception;
            var depth = 0;
            while (current != null && depth < 8)
            {
                if (depth > 0)
                {
                    sb.AppendLine();
                    sb.Append("  -> ");
                }

                sb.Append(current.GetType().Name).Append(": ").Append(current.Message);
                if (!string.IsNullOrWhiteSpace(current.StackTrace) && depth == 0)
                {
                    sb.AppendLine();
                    sb.Append(current.StackTrace);
                }

                current = current.InnerException;
                depth++;
            }

            return sb.ToString();
        }

        private static void Write(string level, string category, string message, Exception exception)
        {
            if (!IsEnabled)
            {
                return;
            }

            try
            {
                var line = new StringBuilder();
                line.Append(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));
                line.Append(" [").Append(level).Append("] ");
                line.Append("[").Append(category).Append("] ");
                line.Append(message);

                if (exception != null)
                {
                    line.AppendLine();
                    line.Append(FormatException(exception));
                }

                lock (Sync)
                {
                    Directory.CreateDirectory(LogDirectory);
                    File.AppendAllText(CurrentLogFilePath, line + Environment.NewLine, Encoding.UTF8);
                }

                Debug.WriteLine(line.ToString());
            }
            catch
            {
                // Logging must never break the app.
            }
        }

        private static string Truncate(string text)
        {
            if (string.IsNullOrEmpty(text) || text.Length <= MaxBodyLength)
            {
                return text ?? string.Empty;
            }

            return text.Substring(0, MaxBodyLength) + "...[truncated]";
        }
    }
}
