using System;
using System.Net.Http;
using System.Net.Http.Json;
using System.Text;
using System.Threading.Tasks;
using Serilog.Core;
using Serilog.Events;

namespace TaxBaik.Web.Logging;

public class TelegramSink : ILogEventSink
{
    private readonly string _botToken;
    private readonly string _chatId;
    private readonly HttpClient _httpClient;

    public TelegramSink(string botToken, string chatId)
    {
        _botToken = botToken;
        _chatId = chatId;
        _httpClient = new HttpClient();
    }

    public void Emit(LogEvent logEvent)
    {
        if (logEvent.Level < LogEventLevel.Error)
        {
            return;
        }

        // Filter out harmless client disconnect and task cancellation exceptions
        if (logEvent.Exception != null)
        {
            var exTypeName = logEvent.Exception.GetType().FullName ?? "";
            var exMessage = logEvent.Exception.Message ?? "";
            if (exTypeName.Contains("JSDisconnectedException") ||
                exTypeName.Contains("TaskCanceledException") ||
                exMessage.Contains("JavaScript interop calls cannot be issued") ||
                exMessage.Contains("circuit has disconnected"))
            {
                return;
            }
        }

        // Emit is a synchronous method, so we dispatch the network call asynchronously
        Task.Run(async () =>
        {
            try
            {
                var timestamp = logEvent.Timestamp.ToString("yyyy-MM-dd HH:mm:ss.fff zzz");
                var level = logEvent.Level.ToString().ToUpper();
                var message = logEvent.RenderMessage();
                var exceptionDetails = logEvent.Exception?.ToString();
                var fingerprint = $"{level}|{message}|{exceptionDetails ?? string.Empty}";
                if (!TaxBaik.Web.Services.TelegramAlertGate.ShouldSend("telegram:sink:error", fingerprint, TimeSpan.FromMinutes(10)))
                {
                    return;
                }

                var sb = new StringBuilder();
                sb.AppendLine($"<b>🚨 [{level}] 에러 발생</b>");
                sb.AppendLine($"<b>시간:</b> {timestamp}");
                sb.AppendLine($"<b>메시지:</b> {EscapeHtml(message)}");

                if (!string.IsNullOrEmpty(exceptionDetails))
                {
                    var escapedException = EscapeHtml(exceptionDetails);
                    if (escapedException.Length > 3000)
                    {
                        escapedException = escapedException.Substring(0, 3000) + "\n[이하 생략]";
                    }
                    sb.AppendLine($"<b>Exception 상세:</b>\n<pre>{escapedException}</pre>");
                }

                var url = $"https://api.telegram.org/bot{_botToken}/sendMessage";
                var payload = new
                {
                    chat_id = _chatId,
                    text = sb.ToString(),
                    parse_mode = "HTML"
                };

                var response = await _httpClient.PostAsJsonAsync(url, payload);
                if (!response.IsSuccessStatusCode)
                {
                    var errorResponse = await response.Content.ReadAsStringAsync();
                    Console.WriteLine($"[TelegramSink] Failed to send log to Telegram: {response.StatusCode} - {errorResponse}");
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[TelegramSink] Error in TelegramSink: {ex.Message}");
            }
        });
    }

    private static string EscapeHtml(string text)
    {
        if (string.IsNullOrEmpty(text)) return text;
        return text.Replace("&", "&amp;")
                   .Replace("<", "&lt;")
                   .Replace(">", "&gt;");
    }
}
