using Forwarder.Domain;
using Forwarder.Models;

using Microsoft.Extensions.Options;

using Monitoring.Contracts;

using Serilog;

using TelegramSender;

namespace Forwarder.Services.Implementations;

/// <inheritdoc />
public class SendService(
	IOptions<ForwarderOptions> options,
	IHttpClientFactory httpClientFactory,
	INotificationBroker notificationBroker
) : ISendService
{
	/// <inheritdoc />
	public async Task<Result> Send(Message message, Guid assetId, CancellationToken cancellationToken)
	{
		try
		{
			var client = httpClientFactory.CreateClient(HttpClients.Api);
			var code = GetCode(message);

			var response = await client.PostAsJsonAsync(
				"/api/events",
				new CreateEventRequest(
					options.Value.ApiToken,
					assetId,
					code,
					message.Sector,
					message.Zone,
					message.CreatedAt,
					new AutoAssetCreating(message.Abonent)),
				cancellationToken);

			_ = response.EnsureSuccessStatusCode();

			var eventId = await response.Content.ReadAsStringAsync(cancellationToken);

			Log.Information("Получен ответ от API, EventId: {EventId}", eventId);

			return Result.Success();
		}
		catch (HttpRequestException ex)
		{
			// Ловим HttpRequestException
			Log.Error(ex, "Request failed: {Message}", ex.Message);

			// Если есть статусный код в ответе, можем его получить
			if (ex.StatusCode.HasValue)
			{
				Log.Error("Status code: {Code}: {Desc}", (int)ex.StatusCode, ex.StatusCode);
			}

			// Получаем весь ответ, если он есть (нужно расширять в .NET 5 и выше)
			if (ex.Data["HttpResponseMessage"] is HttpResponseMessage innerResponse)
			{
				var errorContent = await innerResponse.Content.ReadAsStringAsync(cancellationToken);
				Log.Error("Error response: {ErrorContent}", errorContent);
			}

			await notificationBroker.Enqueue("Forwarder cannot send message: " + ex.Message);

			return Result.Fail(ex.Message);
		}
		catch (Exception ex)
		{
			Log.Error(ex, "Не удалось отправить сообщение: {Type}: {Message}", ex.GetType(), ex.Message);
			return Result.Fail(ex.Message);
		}
	}

	/// <inheritdoc />
	public async Task<Result> SendOnlineStatus(
		bool isOnline,
		Guid assetId,
		CancellationToken cancellationToken)
	{
		try
		{
			var client = httpClientFactory.CreateClient(HttpClients.Api);

			var response = await client.PostAsJsonAsync(
				"/api/assets/online-status",
				new UpdateAssetOnlineStatusRequest(
					options.Value.ApiToken,
					assetId,
					isOnline),
				cancellationToken);

			_ = response.EnsureSuccessStatusCode();

			Log.Information("Статус успешно обновлен");

			return Result.Success();
		}
		catch (HttpRequestException ex)
		{
			// Ловим HttpRequestException
			Log.Error(ex, "Request failed: {Message}", ex.Message);

			// Если есть статусный код в ответе, можем его получить
			if (ex.StatusCode.HasValue)
			{
				Log.Error("Status code: {Code}: {Desc}", (int)ex.StatusCode, ex.StatusCode);
			}

			// Получаем весь ответ, если он есть (нужно расширять в .NET 5 и выше)
			if (ex.Data["HttpResponseMessage"] is HttpResponseMessage innerResponse)
			{
				var errorContent = await innerResponse.Content.ReadAsStringAsync(cancellationToken);
				Log.Error("Error response: {ErrorContent}", errorContent);
			}

			await notificationBroker.Enqueue("Forwarder cannot send message: " + ex.Message);

			return Result.Fail(ex.Message);
		}
		catch (Exception ex)
		{
			Log.Error(ex, "Не удалось отправить сообщение: {Type}: {Message}", ex.GetType(), ex.Message);
			return Result.Fail(ex.Message);
		}
	}
	public async Task<Result> SendTestMessage(Message message, Guid assetId, CancellationToken cancellationToken)
{
    try
    {
        var client = httpClientFactory.CreateClient(HttpClients.Api);
        
        var response = await client.PostAsJsonAsync(
            "/api/events",
            new CreateEventRequest(
                options.Value.ApiToken,
                assetId,
                options.Value.TestMessageEventCode, 
                message.Sector,
                message.Zone,
                message.CreatedAt,
                new AutoAssetCreating(message.Abonent)),
            cancellationToken);

        _ = response.EnsureSuccessStatusCode();
        
        Log.Information("Тестовое сообщение (код {Code}) отправлено, AssetId: {AssetId}", options.Value.TestMessageEventCode, assetId);
        return Result.Success();
    }
    catch (Exception ex)
    {
        Log.Error(ex, "Не удалось отправить тестовое сообщение (код {Code})", options.Value.TestMessageEventCode);
        return Result.Fail(ex.Message);
    }
}
	     

	private static int GetCode(Message message)
	{
		var typePostfix = message.Type switch
		{
			MessageType.AlarmDisarming => 1,
			_ => 3,
		};

		return message.Code * 10 + typePostfix;
	}
}
