// Copyright (C) 2015-2026 The Neo Project.
//
// MethodToken.cs file belongs to the neo project and is free
// software distributed under the MIT software license, see the
// accompanying file LICENSE in the main directory of the
// repository or http://www.opensource.org/licenses/mit-license.php
// for more details.
//
// Redistribution and use in source and binary forms with or without
// modifications are permitted.

using Neo.Extensions;
using Neo.IO;
using Neo.Json;
using System;
using System.IO;

namespace Neo.SmartContract
{
    /// <summary>
    /// Represents the methods that a contract will call statically.
    /// </summary>
    public class MethodToken : ISerializable
    {
        /// <summary>
        /// The hash of the contract to be called.
        /// </summary>
        public required UInt160 Hash;

        /// <summary>
        /// The name of the method to be called.
        /// </summary>
        public required string Method;

        /// <summary>
        /// The number of parameters of the method to be called.
        /// </summary>
        public ushort ParametersCount;

        /// <summary>
        /// Indicates whether the method to be called has a return value.
        /// </summary>
        public bool HasReturnValue;

        /// <summary>
        /// The <see cref="CallFlags"/> to be used to call the contract.
        /// </summary>
        public CallFlags CallFlags;

        public int Size =>
            UInt160.Length +        // Hash
            Method.GetVarSize() +   // Method
            sizeof(ushort) +        // ParametersCount
            sizeof(bool) +          // HasReturnValue
            sizeof(CallFlags);      // CallFlags

        void ISerializable.Deserialize(ref MemoryReader reader)
        {
            Hash = reader.ReadSerializable<UInt160>();
            Method = reader.ReadVarString(32);
            if (Method.StartsWith('_')) throw new FormatException($"Method('{Method}') cannot start with '_'");
            ParametersCount = reader.ReadUInt16();
            HasReturnValue = reader.ReadBoolean();
            CallFlags = (CallFlags)reader.ReadByte();
            if ((CallFlags & ~CallFlags.All) != 0) throw new FormatException($"CallFlags({CallFlags}) is not valid");
        }

        void ISerializable.Serialize(BinaryWriter writer)
        {
            writer.Write(Hash);
            writer.WriteVarString(Method);
            writer.Write(ParametersCount);
            writer.Write(HasReturnValue);
            writer.Write((byte)CallFlags);
        }

        /// <summary>
        /// Converts the token to a JSON object.
        /// </summary>
        /// <returns>The token represented by a JSON object.</returns>
        public JObject ToJson()
        {
            return new JObject
            {
                ["hash"] = Hash.ToString(),
                ["method"] = Method,
                ["paramcount"] = ParametersCount,
                ["hasreturnvalue"] = HasReturnValue,
                ["callflags"] = CallFlags
            };
        }
    }
}
