using System.Text.RegularExpressions;

using Forwarder.Domain;
using Forwarder.Models;

namespace Forwarder.Services.Implementations.MessageConverters;

/// <summary>
/// SurGard Version 4 message converter.
/// </summary>
internal class SurGardVersion4MessageConverter : IMessageConverter
{
	private static readonly Regex Regex = new(@"5(\d{2})(\d{1})\s{1}18(\d{4,16})(\w{1})(\d{3})(\d{2})(\d{3})" + (char)20);
	private static readonly Regex RegexTest = new($@"1011(\s+)@" + (char)20);
	private static readonly IEnumerable<Regex> AllRegex = [Regex, RegexTest];
	private static readonly byte[] AcknowledgeSurGardResponseData = [0x06]; // Encoding.ASCII.GetBytes(AcknowledgeSurGardResponse);

	/// <inheritdoc />
	public string Name => "Sur-Gard Version 4";

	public Result<string> ToText(Message message)
	{
		// 5RRLs18AAAAQCCCSSZZZ[DC4]
		// 5000 1800000281R37300001

		if (message.Type is MessageType.StatePing or MessageType.Unknown)
		{
			return Result<string>.Success($"1011           {(char)20}");
		}

		return Result<string>.Success(
			$"5{message.Receiver:00}{message.Line:0} 18{message.Abonent:0000000000000000}{GetMessageTypeSymbol(message.Type):P}{message.Code:000}{message.Sector:00}{message.Zone:000}{(char)20}");
	}

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

	public Result<Message> Parse(string source)
	{
		// 012345678901234567890
		// 5RRLs18AAAAaaaaQXYZGGCCC[DC4]
		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";
		}

		return new Message(
			Guid.NewGuid(),
			int.Parse(match.Groups[1].Value),
			int.Parse(match.Groups[2].Value),
			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[7].Value),
			DateTime.UtcNow
		);
	}

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

	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);
		}
	}

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