using System;
using System.Globalization;
using System.IO.Ports;
using System.Linq;
using QCRPG.Framework;
using QCRPG.TSL.ZigBee.Packets;

namespace QCRPG.TSL.ZigBee;

public class ZigBeeScripter : ScripterBase
{
	private const int defaultResponseWaitTimeMs = 5000;

	private ZigBeeAPI zigBeeAPI;

	protected ZigBeePacketList zigBeePacketList;

	public ZigBeeScripter(ZigBeeAPI zigBeeAPI, ZigBeePacketList zigBeePacketList)
	{
		this.zigBeeAPI = zigBeeAPI;
		this.zigBeePacketList = zigBeePacketList;
		modeAgnosticDataReceiver = new ModeAgnosticDataReceiver(this.zigBeeAPI);
		tclCommandMap.Add("ZigBee_OpenComPort", ZigBee_OpenComPort_Handler);
		tclCommandMap.Add("ZigBee_CloseComPort", ZigBee_CloseComPort_Handler);
		tclCommandMap.Add("VS_POKE", VS_POKE_Handler);
		tclCommandMap.Add("VS_Poke", VS_POKE_Handler);
		tclCommandMap.Add("VS_PEEK", VS_PEEK_Handler);
		tclCommandMap.Add("VS_Peek", VS_PEEK_Handler);
	}

	private TclResult ZigBee_OpenComPort_Handler(string[] args)
	{
		try
		{
			if (args.Length == 3)
			{
				zigBeeAPI.OpenConnection(args[1], int.Parse(args[2]), Handshake.None);
			}
			else if (args.Length == 4)
			{
				if (args[3].ToUpper() == "NONE")
				{
					zigBeeAPI.OpenConnection(args[1], int.Parse(args[2]), Handshake.None);
				}
				else if (args[3].ToUpper() == "HW")
				{
					zigBeeAPI.OpenConnection(args[1], int.Parse(args[2]), Handshake.RequestToSend);
				}
			}
		}
		catch (Exception ex)
		{
			TclWrapper.SetResult($"Caught exception open ZigBee port.\r\nSource: {ex.Source}\r\nMessage: {ex.Message}");
			return TclResult.ERROR;
		}
		TclWrapper.SetResult("");
		return TclResult.OK;
	}

	private TclResult ZigBee_CloseComPort_Handler(string[] args)
	{
		try
		{
			zigBeeAPI.CloseConnection();
		}
		catch (Exception ex)
		{
			TclWrapper.SetResult($"Caught exception closing connection.\r\nSource: {ex.Source}\r\nMessage: {ex.Message}");
			return TclResult.ERROR;
		}
		TclWrapper.SetResult("");
		return TclResult.OK;
	}

	private TclResult VS_POKE_Handler(string[] args)
	{
		try
		{
			if (args.Length != 6)
			{
				TclWrapper.SetResult($"Wrong # of arguments.  Usage: {args[0]} ?ElementSize? ?NumElements? ?Address? ?Length? ?Data? ...");
				return TclResult.ERROR;
			}
			if (!zigBeeAPI.IsConnectionOpen())
			{
				TclWrapper.SetResult("Connection closed");
				return TclResult.ERROR;
			}
			VsPokeRequest vsPokeRequest = new VsPokeRequest();
			vsPokeRequest.UserFields.Elementsize = uint.Parse(args[1]);
			vsPokeRequest.UserFields.Numelements = uint.Parse(args[2]);
			vsPokeRequest.UserFields.Address = Convert.ToUInt32(args[3], 16);
			vsPokeRequest.UserFields.Datalength = uint.Parse(args[4]);
			string s = args[5].Replace(" ", "");
			if (s.Length % 2 != 0)
			{
				TclWrapper.SetResult($"Wrong # of payLoad.");
				return TclResult.ERROR;
			}
			if (s.StartsWith("0x"))
			{
				s = s.Remove(0, 2);
			}
			uint[] array = (from y in Enumerable.Range(0, s.Length / 2)
				select uint.Parse(s.Substring(2 * y, 2), NumberStyles.HexNumber)).ToArray();
			vsPokeRequest.UserFields.DataList.Clear();
			uint[] array2 = array;
			foreach (uint item in array2)
			{
				vsPokeRequest.UserFields.DataList.Add(item);
			}
			zigBeeAPI.Send(vsPokeRequest);
			TclWrapper.SetResult("");
			return TclResult.OK;
		}
		catch (Exception)
		{
			TclWrapper.SetResult($"Error doing VS_POKE");
			return TclResult.ERROR;
		}
	}

	private TclResult VS_PEEK_Handler(string[] args)
	{
		int num = 0;
		if (args.Length != 4)
		{
			TclWrapper.SetResult($"Wrong # of arguments. Usage: {args[0]} ?ElementSize? ?NumElements? ?Address? ");
			return TclResult.ERROR;
		}
		if (!zigBeeAPI.IsConnectionOpen())
		{
			TclWrapper.SetResult("Connection closed");
			return TclResult.ERROR;
		}
		try
		{
			num = Convert.ToInt32(args[3], 16);
		}
		catch (Exception)
		{
			TclWrapper.SetResult($"Error converting address {args[3]} to an int");
			return TclResult.ERROR;
		}
		try
		{
			VsPeekRequest vsPeekRequest = new VsPeekRequest();
			vsPeekRequest.UserFields.Elementsize = uint.Parse(args[1]);
			vsPeekRequest.UserFields.Numelements = uint.Parse(args[2]);
			vsPeekRequest.UserFields.Address = (uint)num;
			zigBeeAPI.Send(vsPeekRequest);
		}
		catch (Exception ex2)
		{
			TclWrapper.SetResult($"Caught exception sending peek byte, {args[1]}.\r\nSource: {ex2.Source}\r\nMessage: {ex2.Message}");
			return TclResult.ERROR;
		}
		VsPeekConfirmation vsPeekConfirmation;
		try
		{
			vsPeekConfirmation = (VsPeekConfirmation)modeAgnosticDataReceiver.Receive(typeof(VsPeekConfirmation), 5000);
		}
		catch (Exception ex3)
		{
			TclWrapper.SetResult($"Caught exception waiting for response to peek , {args[1]}.\r\nSource: {ex3.Source}\r\nMessage: {ex3.Message}");
			return TclResult.ERROR;
		}
		byte[] byteArray = Conversions.UintListToByteArray(vsPeekConfirmation.UserFields.DataList);
		TclWrapper.SetResult(Conversions.ByteArrayTo0xHexString(byteArray, singlePrefix: true));
		return TclResult.OK;
	}
}
