using System.Globalization;
using System.Text.RegularExpressions;
using Forwarder.Domain;
using Forwarder.Models;
using Serilog;

namespace Forwarder.Services.Implementations.MessageConverters;

internal class Ademco685MessageConverter : IMessageConverter
{
	private static readonly Regex Regex = new(
		$@"{(char)10}(\d{{1}})(\d{{1}})\s{{1}}(\d{{4}})\s{{1}}18\s{{1}}(\w{{1}})(\d{{3}})\s{{1}}(\d{{2}})\s{{1}}(\w{{1}})(\d{{3}})\s{{1}}{(char)13}"
	);
	private static readonly Regex RegexTest = new(
		$@"{(char)10}(\d{{2}})\s{{1}}OKAY\s{{1}}@{(char)13}"
	);
	private static readonly IEnumerable<Regex> AllRegex = [Regex, RegexTest];

	private const byte AcknowledgeSurGardResponse = 0x06;
	private static readonly byte[] AcknowledgeSurGardResponseData = [AcknowledgeSurGardResponse];

	/// <inheritdoc />
	public string Name => "Ademco 685";

	private static string GetMessageTypeSymbol(MessageType type)
	{
		return type switch
		{
			MessageType.AlarmDisarming => "E",
			MessageType.RecoveryArming => "R",
			MessageType.StatePing => "P",
			_ => "",
		};
	}

	private static MessageType GetMessageType(string s)
	{
		return s switch
		{
			"E" => MessageType.AlarmDisarming,
			"R" => MessageType.RecoveryArming,
			"P" => MessageType.StatePing,
			_ => MessageType.Unknown,
		};
	}

	public Result<string> ToText(Message message)
	{
		// [LF]RLsAAAAs18sQXYZsGGsUCCC[CR]
		return Result<string>.Success(
			$"{(char)10}{message.Receiver:0}{message.Line:0} {message.Abonent:0000} 18 {GetMessageTypeSymbol(message.Type):P}{message.Code:000} {message.Sector:00} C{message.Zone:000}{(char)13}"
		);
	}

	public Result<Message> Parse(string source)
	{
		var match = RegexTest.Match(source);
		if (match.Success)
		{
			return new Message(
				Guid.NewGuid(),
				int.Parse(match.Groups[1].Value),
				int.Parse(match.Groups[2].Value),
				"",
				MessageType.StatePing,
				0,
				0,
				0,
				DateTime.UtcNow
			);
		}

		match = Regex.Match(source);
		if (!match.Success)
		{
			return "Invalid message format";
		}

		// [LF]RLsAAAAs18sQXYZsGGsUCCC[CR]
		return new Message(
			Guid.NewGuid(),
			int.Parse(match.Groups[1].Value),
			int.Parse(match.Groups[2].Value),
			ConvertAbonent(match.Groups[3].Value),
			GetMessageType(match.Groups[4].Value),
			int.Parse(match.Groups[5].Value),
			int.Parse(match.Groups[6].Value),
			int.Parse(match.Groups[8].Value),
			DateTime.UtcNow
		);
	}

	private static string ConvertAbonent(string value)
	{
		var hex = int.Parse(value, NumberStyles.HexNumber);
		Log.Warning("Parsed: {Hex}", hex);
		return hex.ToString();
	}

	public bool CanHandle(string messageText)
	{
		return AllRegex.Any(x => x.IsMatch(messageText));
	}

	public async Task<Result> SendAnswer(
		INetworkSender networkSender,
		CancellationToken cancellationToken
	)
	{
		try
		{
			await networkSender.SendAsync(AcknowledgeSurGardResponseData, cancellationToken);
			return Result.Success();
		}
		catch (Exception ex)
		{
			return Result.Fail(ex.Message);
		}
	}
}
