﻿﻿﻿﻿﻿﻿﻿﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using Serilog;
using Serilog.Core;
using Serilog.Events;
using Serilog.Formatting.Json;
using Serilog.Sinks.Http;
using Microsoft.Extensions.Configuration;

namespace CamBooth.App.Core.Logging;

public class Logger : IDisposable
{
	private readonly Serilog.Core.Logger _serilogLogger;

	public event LoggingEventHandler? InfoLog;
	public event LoggingEventHandler? ErrorLog;
	public event LoggingEventHandler? WarningLog;
	public event LoggingEventHandler? DebugLog;
	public delegate void LoggingEventHandler(string text);

	public Logger(IConfiguration configuration)
	{
		var logLevel = configuration["LoggingSettings:LogLevel"] ?? "Information";
		var logDirectoryInput = configuration["LoggingSettings:LogDirectory"] ?? "Logs";
		var remoteServerUrl = configuration["LoggingSettings:RemoteServerUrl"];
		var remoteServerApiKey = configuration["LoggingSettings:RemoteServerApiKey"];

		// Konvertiere zu absolutem Pfad
		var logDirectory = Path.IsPathRooted(logDirectoryInput)
			? logDirectoryInput
			: Path.Combine(AppDomain.CurrentDomain.BaseDirectory, logDirectoryInput);

		// Erstelle Verzeichnis, falls nicht vorhanden
		if (!Directory.Exists(logDirectory))
		{
			Directory.CreateDirectory(logDirectory);
		}

		var minimumLevel = ParseLogLevel(logLevel);

		var loggerConfig = new LoggerConfiguration()
			.MinimumLevel.Is(minimumLevel)
			.MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
			.MinimumLevel.Override("System", LogEventLevel.Warning)
			.Enrich.FromLogContext()
			.Enrich.WithProperty("Application", "CamBooth")
			.WriteTo.Console(
				outputTemplate: "{Timestamp:dd.MM.yyyy HH:mm:ss} [{Level:u3}] {Message:lj}{NewLine}{Exception}")
			.WriteTo.File(
				Path.Combine(logDirectory, "cambooth-.log"),
				rollingInterval: RollingInterval.Day,
				retainedFileCountLimit: 30,
				outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff} [{Level:u3}] {Message:lj}{NewLine}{Exception}");
		
		if (!string.IsNullOrWhiteSpace(remoteServerUrl))
		{
			try
			{
				loggerConfig.WriteTo.Seq(
					serverUrl: remoteServerUrl,       
					apiKey: remoteServerApiKey,       
					restrictedToMinimumLevel: minimumLevel
				);

				Console.WriteLine($"Seq Sink konfiguriert: {remoteServerUrl}");
			}
			catch (Exception ex)
			{
				Console.WriteLine($"Fehler beim Konfigurieren des Seq-Sinks: {ex.Message}");
			}
		}

		_serilogLogger = loggerConfig.CreateLogger();

		Log.Logger = _serilogLogger;

		Info($"Serilog Logger initialisiert - Level: {logLevel}, Directory: {logDirectory}");
		if (!string.IsNullOrWhiteSpace(remoteServerUrl))
		{
			Info($"Remote Server konfiguriert: {remoteServerUrl}");
		}
	}

	private LogEventLevel ParseLogLevel(string level)
	{
		return level.ToLowerInvariant() switch
		{
			"verbose" => LogEventLevel.Verbose,
			"debug" => LogEventLevel.Debug,
			"information" => LogEventLevel.Information,
			"warning" => LogEventLevel.Warning,
			"error" => LogEventLevel.Error,
			"fatal" => LogEventLevel.Fatal,
			_ => LogEventLevel.Information
		};
	}

	public void Info(string message)
	{
		try
		{
			if (Application.Current?.Dispatcher != null)
			{
				Application.Current.Dispatcher.Invoke(() =>
				{
					var formattedMessage = DateTime.Now.ToString("dd.MM.yyyy HH:mm:ss", CultureInfo.InvariantCulture) + ": [INFO] " + message;
					InfoLog?.Invoke(formattedMessage);
				});
			}
			
			_serilogLogger.Information(message);
		}
		catch (Exception ex)
		{
			Console.WriteLine($"Fehler beim Info-Logging: {ex.Message}");
		}
	}

	public void Warning(string message)
	{
		try
		{
			if (Application.Current?.Dispatcher != null)
			{
				Application.Current.Dispatcher.Invoke(() =>
				{
					var formattedMessage = DateTime.Now.ToString("dd.MM.yyyy HH:mm:ss", CultureInfo.InvariantCulture) + ": [WARNING] " + message;
					WarningLog?.Invoke(formattedMessage);
				});
			}
			
			_serilogLogger.Warning(message);
		}
		catch (Exception ex)
		{
			Console.WriteLine($"Fehler beim Warning-Logging: {ex.Message}");
		}
	}

	public void Error(string message)
	{
		try
		{
			if (Application.Current?.Dispatcher != null)
			{
				Application.Current.Dispatcher.Invoke(() =>
				{
					var formattedMessage = DateTime.Now.ToString("dd.MM.yyyy HH:mm:ss", CultureInfo.InvariantCulture) + ": [ERROR] " + message;
					ErrorLog?.Invoke(formattedMessage);
				});
			}
			
			_serilogLogger.Error(message);
		}
		catch (Exception ex)
		{
			Console.WriteLine($"Fehler beim Error-Logging: {ex.Message}");
		}
	}

	public void Error(string message, Exception exception)
	{
		try
		{
			if (Application.Current?.Dispatcher != null)
			{
				Application.Current.Dispatcher.Invoke(() =>
				{
					var formattedMessage = DateTime.Now.ToString("dd.MM.yyyy HH:mm:ss", CultureInfo.InvariantCulture) + ": [ERROR] " + message;
					ErrorLog?.Invoke(formattedMessage);
				});
			}
			
			_serilogLogger.Error(exception, message);
		}
		catch (Exception ex)
		{
			Console.WriteLine($"Fehler beim Error-Logging: {ex.Message}");
		}
	}

	public void Debug(string message)
	{
		try
		{
			if (Application.Current?.Dispatcher != null)
			{
				Application.Current.Dispatcher.Invoke(() =>
				{
					var formattedMessage = DateTime.Now.ToString("dd.MM.yyyy HH:mm:ss", CultureInfo.InvariantCulture) + ": [DEBUG] " + message;
					DebugLog?.Invoke(formattedMessage);
				});
			}
			
			_serilogLogger.Debug(message);
		}
		catch (Exception ex)
		{
			Console.WriteLine($"Fehler beim Debug-Logging: {ex.Message}");
		}
	}

	public void Dispose()
	{
		_serilogLogger?.Dispose();
		Log.CloseAndFlush();
	}
}