﻿using System;
using System.Linq;
using Trinity.Cryptography;
using Trinity.Extensions;
using Trinity.Settings;

namespace Trinity.Wallets
{
	/// <summary>
	///     Extension methods related to wallet function.
	///     If a single type becomes dominant it will be extracted into it's own extension method class.
	/// </summary>
	public static class WalletExtensions
	{
		/// <summary>
		///     Convert a script hash to address
		/// </summary>
		/// <param name="scriptHash"></param>
		/// <param name="addressVersion">optional address version, defaults to protocol.addressversion</param>
		/// <returns></returns>
		public static string ToAddress(this UInt160 scriptHash, byte addressVersion = 0)
		{
			var data = new byte[21];
			data[0] = addressVersion == 0 ? Config.ProtocolSettings.AddressVersion : addressVersion;
			Buffer.BlockCopy(scriptHash.ToArray(), 0, data, 1, 20);
			return data.Base58CheckEncode();
		}

		public static UInt160 ToScriptHash(this string address, byte addressVersion = 0)
		{
			var v = addressVersion == 0 ? Config.ProtocolSettings.AddressVersion : addressVersion;
			var data = address.Base58CheckDecode();
			if (data.Length != 21)
			{
				throw new FormatException();
			}
			if (data[0] != v)
			{
				throw new FormatException();
			}
			return new UInt160(data.Skip(1).ToArray());
		}


		/// <summary>
		///     Gets a private key from a wallet import format.
		///     https://en.bitcoin.it/wiki/Wallet_import_format
		/// </summary>
		/// <param name="wif"></param>
		/// <returns></returns>
		public static byte[] GetPrivateKeyFromWalletImportFormat(this string wif)
		{
			if (wif == null)
			{
				throw new ArgumentNullException();
			}
			var data = wif.Base58CheckDecode();
			if (data.Length != 34 || data[0] != 0x80 || data[33] != 0x01)
			{
				throw new FormatException();
			}
			var privateKey = new byte[32];
			Buffer.BlockCopy(data, 1, privateKey, 0, privateKey.Length);
			Array.Clear(data, 0, data.Length);
			return privateKey;
		}
	}
}