using System.Buffers;
using System.Numerics;
using System.Text.Json;

namespace HyperMath.Core
{
    /// <summary>
    /// Represents a multi-dimensional tensor with generic type T.
    /// </summary>
    /// <typeparam name="T">
    /// The type of elements in the tensor. Must be unmanaged and support numeric operations.
    /// </typeparam>
    public class Tensor<T> : IDisposable where T : unmanaged, INumber<T>, IExponentialFunctions<T>, ITrigonometricFunctions<T>
    {
        /// <summary>
        /// Manages the shared data array with reference counting.
        /// </summary>
        private class SharedData
        {
            public T[] Data;
            public int Length => Data.Length;
            public int refCount;

            public SharedData(int size)
            {
                Data = ArrayPool<T>.Shared.Rent(size);
                Array.Clear(Data, 0, size);
                refCount = 1;
            }

            private SharedData(T[] data)
            {
                Data = data;
                refCount = 1;
            }

            public void AddRef()
            {
                Interlocked.Increment(ref refCount);
            }

            public void Release()
            {
                if (Interlocked.Decrement(ref refCount) == 0)
                {
                    ArrayPool<T>.Shared.Return(Data, clearArray: true);
                }
            }

            public SharedData CloneData()
            {
                var newData = ArrayPool<T>.Shared.Rent(Data.Length);
                Array.Copy(Data, newData, Data.Length);
                return new SharedData(newData);
            }
        }

        private SharedData sharedData;
        private readonly int[] shape;
        private readonly int[] strides;
        private int offset;
        private bool disposed = false;

        /// <summary>
        /// Gets the shape of the tensor.
        /// </summary>
        public int[] Shape => (int[])shape.Clone();

        /// <summary>
        /// Gets the total number of elements in the tensor.
        /// </summary>
        public int TotalSize { get; }

        /// <summary>
        /// Threshold for enabling parallelization.
        /// </summary>
        public static int ParallelizationThreshold { get; set; } = 1000;

        #region Constructors

        /// <summary>
        /// Initializes a new tensor with the specified dimensions.
        /// </summary>
        /// <param name="dimensions">Sizes for each dimension.</param>
        public Tensor(params int[] dimensions)
        {
            if (dimensions == null || dimensions.Length == 0)
                throw new ArgumentException("Tensor must have at least one dimension.", nameof(dimensions));

            foreach (var dim in dimensions)
            {
                if (dim <= 0)
                    throw new ArgumentException("Each dimension size must be positive.", nameof(dimensions));
            }

            shape = (int[])dimensions.Clone();
            strides = CalculateStrides(shape);
            TotalSize = shape.Aggregate(1, (a, b) => a * b);
            sharedData = new SharedData(TotalSize);
            offset = 0;
        }

        private Tensor(SharedData sharedData, int[] shape, int[] strides, int offset)
        {
            this.sharedData = sharedData;
            this.shape = shape;
            this.strides = strides;
            this.offset = offset;
            TotalSize = shape.Aggregate(1, (a, b) => a * b);
            sharedData.AddRef();
        }

        #endregion

        #region Indexer and Element Access

        /// <summary>
        /// Gets or sets the element at the specified indices.
        /// </summary>
        /// <param name="indices">Indices array.</param>
        public T this[params int[] indices]
        {
            get
            {
                EnsureNotDisposed();
                int flatIndex = CalculateFlatIndex(indices);
                return sharedData.Data[flatIndex];
            }
            set
            {
                EnsureNotDisposed();
                int flatIndex = CalculateFlatIndex(indices);
                EnsureUniqueData();
                sharedData.Data[flatIndex] = value;
            }
        }

        /// <summary>
        /// Ensures that the data is unique before modifying it.
        /// </summary>
        private void EnsureUniqueData()
        {
            if (sharedData.refCount > 1)
            {
                var newSharedData = sharedData.CloneData();
                sharedData.Release();
                sharedData = newSharedData;
                offset = 0;
            }
        }

        /// <summary>
        /// Calculates the flat index from multi-dimensional indices.
        /// </summary>
        /// <param name="indices">Indices array.</param>
        /// <returns>Flat index.</returns>
        private int CalculateFlatIndex(int[] indices)
        {
            if (indices == null)
                throw new ArgumentNullException(nameof(indices));

            if (indices.Length != shape.Length)
                throw new ArgumentException("Number of indices must match number of tensor dimensions.", nameof(indices));

            int flatIndex = offset;
            for (int i = 0; i < shape.Length; i++)
            {
                if (indices[i] < 0 || indices[i] >= shape[i])
                    throw new ArgumentOutOfRangeException(nameof(indices), $"Index {indices[i]} out of bounds for dimension {i}.");

                flatIndex += indices[i] * strides[i];
            }

            if (flatIndex < 0 || flatIndex >= sharedData.Data.Length)
                throw new IndexOutOfRangeException("Flat index out of range.");

            return flatIndex;
        }

        #endregion

        #region Cloning and Slicing

        /// <summary>
        /// Clones the tensor, creating a new tensor with the same data.
        /// </summary>
        /// <returns>A new tensor cloned from the current tensor.</returns>
        public Tensor<T> Clone()
        {
            EnsureNotDisposed();
            var newSharedData = sharedData.CloneData();
            return new Tensor<T>(newSharedData, (int[])shape.Clone(), (int[])strides.Clone(), offset);
        }

        /// <summary>
        /// Creates a tensor view (slice) from the current tensor.
        /// </summary>
        /// <param name="ranges">Ranges for each dimension.</param>
        /// <returns>A new tensor view.</returns>
        public Tensor<T> Slice(params Range[] ranges)
        {
            EnsureNotDisposed();

            if (ranges == null)
                throw new ArgumentNullException(nameof(ranges));

            if (ranges.Length != shape.Length)
                throw new ArgumentException("Number of ranges must match number of tensor dimensions.", nameof(ranges));

            int[] newShape = new int[shape.Length];
            int newOffset = offset;

            for (int i = 0; i < shape.Length; i++)
            {
                var range = ranges[i];
                int start = range.Start.IsFromEnd ? shape[i] - range.Start.Value : range.Start.Value;
                int end = range.End.IsFromEnd ? shape[i] - range.End.Value : range.End.Value;

                if (start < 0 || end > shape[i] || start > end)
                    throw new ArgumentOutOfRangeException(nameof(ranges), $"Invalid range for dimension {i}.");

                newShape[i] = end - start;
                newOffset += start * strides[i];
            }

            return new Tensor<T>(sharedData, newShape, strides, newOffset);
        }

        /// <summary>
        /// Provides advanced slicing with steps.
        /// </summary>
        /// <param name="ranges">Ranges with steps for each dimension.</param>
        /// <returns>A new tensor view with steps.</returns>
        public Tensor<T> SliceWithSteps(params (int start, int end, int step)[] ranges)
        {
            EnsureNotDisposed();

            if (ranges == null)
                throw new ArgumentNullException(nameof(ranges));

            if (ranges.Length != shape.Length)
                throw new ArgumentException("Number of ranges must match number of tensor dimensions.", nameof(ranges));

            int[] newShape = new int[shape.Length];
            int newOffset = offset;
            int[] newStrides = new int[shape.Length];

            for (int i = 0; i < shape.Length; i++)
            {
                var (start, end, step) = ranges[i];
                if (step <= 0)
                    throw new ArgumentException("Step must be positive.", nameof(ranges));

                if (start < 0 || start >= shape[i])
                    throw new ArgumentOutOfRangeException(nameof(ranges), $"Start index out of bounds for dimension {i}.");

                if (end < start || end > shape[i])
                    throw new ArgumentOutOfRangeException(nameof(ranges), $"End index out of bounds for dimension {i}.");

                newShape[i] = (int)Math.Ceiling((double)(end - start) / step);
                newOffset += start * strides[i];
                newStrides[i] = strides[i] * step;
            }

            return new Tensor<T>(sharedData, newShape, newStrides, newOffset);
        }

        #endregion

        #region Arithmetic Operations

        // Custom delegate types to support ref parameters
        private delegate void ElementWiseOperationDelegate(ref T a, T b);
        private delegate void ScalarOperationDelegate(ref T a, T b);

        // Element-wise operations, in-place operations, and scalar operations

        /// <summary>
        /// Performs element-wise addition with another tensor.
        /// </summary>
        public Tensor<T> Add(Tensor<T> other)
        {
            return ElementWiseOperation(other, (a, b) => a + b);
        }

        /// <summary>
        /// Performs in-place addition with another tensor.
        /// </summary>
        public void AddInPlace(Tensor<T> other)
        {
            InPlaceElementWiseOperation(other, AddOperation);
        }

        // Named method for addition operation
        private void AddOperation(ref T a, T b)
        {
            a = a + b;
        }

        /// <summary>
        /// Asynchronously performs element-wise addition with another tensor.
        /// </summary>
        public async Task<Tensor<T>> AddAsync(Tensor<T> other)
        {
            return await Task.Run(() => Add(other));
        }

        // Similar methods for Subtract, Multiply, Divide, etc.

        public Tensor<T> Subtract(Tensor<T> other)
        {
            return ElementWiseOperation(other, (a, b) => a - b);
        }

        public void SubtractInPlace(Tensor<T> other)
        {
            InPlaceElementWiseOperation(other, SubtractOperation);
        }

        private void SubtractOperation(ref T a, T b)
        {
            a = a - b;
        }

        public async Task<Tensor<T>> SubtractAsync(Tensor<T> other)
        {
            return await Task.Run(() => Subtract(other));
        }

        public Tensor<T> Multiply(Tensor<T> other)
        {
            return ElementWiseOperation(other, (a, b) => a * b);
        }

        public void MultiplyInPlace(Tensor<T> other)
        {
            InPlaceElementWiseOperation(other, MultiplyOperation);
        }

        private void MultiplyOperation(ref T a, T b)
        {
            a = a * b;
        }

        public async Task<Tensor<T>> MultiplyAsync(Tensor<T> other)
        {
            return await Task.Run(() => Multiply(other));
        }

        public Tensor<T> Divide(Tensor<T> other)
        {
            return ElementWiseOperation(other, (a, b) => a / b);
        }

        public void DivideInPlace(Tensor<T> other)
        {
            InPlaceElementWiseOperation(other, DivideOperation);
        }

        private void DivideOperation(ref T a, T b)
        {
            a = a / b;
        }

        public async Task<Tensor<T>> DivideAsync(Tensor<T> other)
        {
            return await Task.Run(() => Divide(other));
        }

        // Scalar operations

        public Tensor<T> AddScalar(T scalar)
        {
            return ScalarOperation(scalar, (a, b) => a + b);
        }

        public void AddScalarInPlace(T scalar)
        {
            InPlaceScalarOperation(scalar, AddScalarOperation);
        }

        private void AddScalarOperation(ref T a, T b)
        {
            a = a + b;
        }

        public Tensor<T> SubtractScalar(T scalar)
        {
            return ScalarOperation(scalar, (a, b) => a - b);
        }

        public void SubtractScalarInPlace(T scalar)
        {
            InPlaceScalarOperation(scalar, SubtractScalarOperation);
        }

        private void SubtractScalarOperation(ref T a, T b)
        {
            a = a - b;
        }

        public Tensor<T> MultiplyScalar(T scalar)
        {
            return ScalarOperation(scalar, (a, b) => a * b);
        }

        public void MultiplyScalarInPlace(T scalar)
        {
            InPlaceScalarOperation(scalar, MultiplyScalarOperation);
        }

        private void MultiplyScalarOperation(ref T a, T b)
        {
            a = a * b;
        }

        public Tensor<T> DivideScalar(T scalar)
        {
            return ScalarOperation(scalar, (a, b) => a / b);
        }

        public void DivideScalarInPlace(T scalar)
        {
            InPlaceScalarOperation(scalar, DivideScalarOperation);
        }

        private void DivideScalarOperation(ref T a, T b)
        {
            a = a / b;
        }


        #endregion

        #region Advanced Operations

        /// <summary>
        /// Performs a matrix multiplication with another tensor.
        /// </summary>
        public Tensor<T> MatMul(Tensor<T> other)
        {
            EnsureNotDisposed();
            other?.EnsureNotDisposed();

            if (other == null)
                throw new ArgumentNullException(nameof(other));

            if (this.shape.Length != 2 || other.shape.Length != 2)
                throw new ArgumentException("MatMul is only supported for 2D tensors.");

            if (this.shape[1] != other.shape[0])
                throw new ArgumentException($"Inner tensor dimensions must match for MatMul. Found {this.shape[1]} and {other.shape[0]}.");

            int m = this.shape[0];
            int n = this.shape[1];
            int p = other.shape[1];

            Tensor<T> result = new Tensor<T>(m, p);

            if (TotalSize >= ParallelizationThreshold)
            {
                Parallel.For(0, m, i =>
                {
                    for (int j = 0; j < p; j++)
                    {
                        T sum = T.Zero;
                        for (int k = 0; k < n; k++)
                        {
                            sum += this[i, k] * other[k, j];
                        }
                        result[i, j] = sum;
                    }
                });
            }
            else
            {
                for (int i = 0; i < m; i++)
                {
                    for (int j = 0; j < p; j++)
                    {
                        T sum = T.Zero;
                        for (int k = 0; k < n; k++)
                        {
                            sum += this[i, k] * other[k, j];
                        }
                        result[i, j] = sum;
                    }
                }
            }

            return result;
        }

        // Implement BatchMatrixMultiply, DotProduct, Transpose, etc., following similar patterns.

        /// <summary>
        /// Transposes the tensor along two specified axes.
        /// </summary>
        public Tensor<T> Transpose(int axis1, int axis2)
        {
            EnsureNotDisposed();

            if (axis1 < 0 || axis1 >= shape.Length)
                throw new ArgumentOutOfRangeException(nameof(axis1), "Axis1 is out of bounds.");

            if (axis2 < 0 || axis2 >= shape.Length)
                throw new ArgumentOutOfRangeException(nameof(axis2), "Axis2 is out of bounds.");

            int[] newShape = (int[])shape.Clone();
            int[] newStrides = (int[])strides.Clone();

            // Swap shape and strides
            (newShape[axis1], newShape[axis2]) = (newShape[axis2], newShape[axis1]);
            (newStrides[axis1], newStrides[axis2]) = (newStrides[axis2], newStrides[axis1]);

            return new Tensor<T>(sharedData, newShape, newStrides, offset);
        }

        #endregion

        #region Helper Methods

        /// <summary>
        /// Performs element-wise operation with another tensor.
        /// </summary>
        private Tensor<T> ElementWiseOperation(Tensor<T> other, Func<T, T, T> operation)
        {
            EnsureNotDisposed();

            if (other == null)
                throw new ArgumentNullException(nameof(other));

            other.EnsureNotDisposed();

            int[] resultShape = DetermineBroadcastShape(this.shape, other.shape);
            Tensor<T> result = new Tensor<T>(resultShape);

            int[] aStridesBroadcasted = ComputeBroadcastStrides(this.shape, resultShape, this.strides);
            int[] bStridesBroadcasted = ComputeBroadcastStrides(other.shape, resultShape, other.strides);

            if (result.TotalSize >= ParallelizationThreshold)
            {
                Parallel.For(0, result.TotalSize, i =>
                {
                    int[] indices = UnflattenIndex(i, resultShape);
                    int aIndex = ComputeFlatIndex(indices, aStridesBroadcasted) + this.offset;
                    int bIndex = ComputeFlatIndex(indices, bStridesBroadcasted) + other.offset;
                    result.sharedData.Data[i] = operation(this.sharedData.Data[aIndex], other.sharedData.Data[bIndex]);
                });
            }
            else
            {
                for (int i = 0; i < result.TotalSize; i++)
                {
                    int[] indices = UnflattenIndex(i, resultShape);
                    int aIndex = ComputeFlatIndex(indices, aStridesBroadcasted) + this.offset;
                    int bIndex = ComputeFlatIndex(indices, bStridesBroadcasted) + other.offset;
                    result.sharedData.Data[i] = operation(this.sharedData.Data[aIndex], other.sharedData.Data[bIndex]);
                }
            }

            return result;
        }

        /// <summary>
        /// Performs in-place element-wise operation with another tensor.
        /// </summary>
        private void InPlaceElementWiseOperation(Tensor<T> other, ElementWiseOperationDelegate operation)
        {
            EnsureNotDisposed();

            if (other == null)
                throw new ArgumentNullException(nameof(other));

            other.EnsureNotDisposed();

            int[] resultShape = DetermineBroadcastShape(this.shape, other.shape);

            if (!this.shape.SequenceEqual(resultShape))
                throw new InvalidOperationException("In-place operation requires the shapes to be broadcastable to the shape of this tensor.");

            EnsureUniqueData();

            int[] aStridesBroadcasted = this.strides;
            int[] bStridesBroadcasted = ComputeBroadcastStrides(other.shape, this.shape, other.strides);

            if (TotalSize >= ParallelizationThreshold)
            {
                Parallel.For(0, TotalSize, i =>
                {
                    int[] indices = UnflattenIndex(i, shape);
                    int aIndex = ComputeFlatIndex(indices, aStridesBroadcasted) + this.offset;
                    int bIndex = ComputeFlatIndex(indices, bStridesBroadcasted) + other.offset;
                    operation(ref sharedData.Data[aIndex], other.sharedData.Data[bIndex]);
                });
            }
            else
            {
                for (int i = 0; i < TotalSize; i++)
                {
                    int[] indices = UnflattenIndex(i, shape);
                    int aIndex = ComputeFlatIndex(indices, aStridesBroadcasted) + this.offset;
                    int bIndex = ComputeFlatIndex(indices, bStridesBroadcasted) + other.offset;
                    operation(ref sharedData.Data[aIndex], other.sharedData.Data[bIndex]);
                }
            }
        }

        /// <summary>
        /// Performs a scalar operation on each element of the tensor.
        /// </summary>
        private Tensor<T> ScalarOperation(T scalar, Func<T, T, T> operation)
        {
            EnsureNotDisposed();

            Tensor<T> result = new Tensor<T>((int[])shape.Clone());

            if (TotalSize >= ParallelizationThreshold)
            {
                Parallel.For(0, TotalSize, i =>
                {
                    result.sharedData.Data[i] = operation(sharedData.Data[offset + i], scalar);
                });
            }
            else
            {
                for (int i = 0; i < TotalSize; i++)
                {
                    result.sharedData.Data[i] = operation(sharedData.Data[offset + i], scalar);
                }
            }

            return result;
        }

        /// <summary>
        /// Performs an in-place scalar operation on each element of the tensor.
        /// </summary>
        private void InPlaceScalarOperation(T scalar, ScalarOperationDelegate operation)
        {
            EnsureNotDisposed();
            EnsureUniqueData();

            if (TotalSize >= ParallelizationThreshold)
            {
                Parallel.For(0, TotalSize, i =>
                {
                    operation(ref sharedData.Data[offset + i], scalar);
                });
            }
            else
            {
                for (int i = 0; i < TotalSize; i++)
                {
                    operation(ref sharedData.Data[offset + i], scalar);
                }
            }
        }

        #endregion

        #region Strides and Index Calculations

        /// <summary>
        /// Calculates the strides for row-major order.
        /// </summary>
        private static int[] CalculateStrides(int[] shape)
        {
            int[] strides = new int[shape.Length];
            strides[shape.Length - 1] = 1;
            for (int i = shape.Length - 2; i >= 0; i--)
            {
                strides[i] = strides[i + 1] * shape[i + 1];
            }
            return strides;
        }

        /// <summary>
        /// Determines the broadcasted shape from two shapes.
        /// </summary>
        private static int[] DetermineBroadcastShape(int[] aShape, int[] bShape)
        {
            int maxLength = Math.Max(aShape.Length, bShape.Length);
            int[] broadcastShape = new int[maxLength];

            for (int i = 0; i < maxLength; i++)
            {
                int aDim = i < maxLength - aShape.Length ? 1 : aShape[i - (maxLength - aShape.Length)];
                int bDim = i < maxLength - bShape.Length ? 1 : bShape[i - (maxLength - bShape.Length)];

                if (aDim != bDim && aDim != 1 && bDim != 1)
                    throw new InvalidOperationException($"Shapes {string.Join(",", aShape)} and {string.Join(",", bShape)} are not broadcastable.");

                broadcastShape[i] = Math.Max(aDim, bDim);
            }

            return broadcastShape;
        }

        /// <summary>
        /// Computes broadcasted strides for a tensor based on the result shape.
        /// </summary>
        private static int[] ComputeBroadcastStrides(int[] originalShape, int[] resultShape, int[] originalStrides)
        {
            int originalLength = originalShape.Length;
            int resultLength = resultShape.Length;
            int[] broadcastStrides = new int[resultLength];

            int sizeDifference = resultLength - originalLength;
            for (int i = resultLength - 1; i >= 0; i--)
            {
                if (i - sizeDifference >= 0 && originalShape[i - sizeDifference] == resultShape[i])
                {
                    broadcastStrides[i] = originalStrides[i - sizeDifference];
                }
                else if (i - sizeDifference >= 0 && originalShape[i - sizeDifference] == 1)
                {
                    broadcastStrides[i] = 0;
                }
                else if (i - sizeDifference < 0)
                {
                    broadcastStrides[i] = 0;
                }
                else
                {
                    throw new InvalidOperationException("Shapes are not broadcastable.");
                }
            }

            return broadcastStrides;
        }

        /// <summary>
        /// Converts a flat index to multi-dimensional indices based on the shape.
        /// </summary>
        private static int[] UnflattenIndex(int flatIndex, int[] shape)
        {
            int[] indices = new int[shape.Length];
            for (int i = shape.Length - 1; i >= 0; i--)
            {
                indices[i] = flatIndex % shape[i];
                flatIndex /= shape[i];
            }
            return indices;
        }

        /// <summary>
        /// Computes the flat index from multi-dimensional indices and strides.
        /// </summary>
        private static int ComputeFlatIndex(int[] indices, int[] strides)
        {
            int flatIndex = 0;
            for (int i = 0; i < indices.Length; i++)
            {
                flatIndex += indices[i] * strides[i];
            }
            return flatIndex;
        }

        #endregion

        #region Dispose Pattern

        /// <summary>
        /// Ensures that the tensor has not been disposed.
        /// </summary>
        private void EnsureNotDisposed()
        {
            if (disposed)
                throw new ObjectDisposedException(nameof(Tensor<T>));
        }

        /// <summary>
        /// Dispose pattern implementation.
        /// </summary>
        public void Dispose()
        {
            if (!disposed)
            {
                sharedData.Release();
                disposed = true;
            }
        }

        #endregion

        #region Visualization and Serialization

        /// <summary>
        /// Displays the tensor data for debugging purposes.
        /// </summary>
        public void Display()
        {
            EnsureNotDisposed();

            if (shape.Length == 1)
            {
                Console.Write("[");
                for (int i = 0; i < shape[0]; i++)
                {
                    Console.Write(this[i]);
                    if (i < shape[0] - 1)
                        Console.Write(", ");
                }
                Console.WriteLine("]");
            }
            else if (shape.Length == 2)
            {
                for (int i = 0; i < shape[0]; i++)
                {
                    Console.Write("[");
                    for (int j = 0; j < shape[1]; j++)
                    {
                        Console.Write(this[i, j]);
                        if (j < shape[1] - 1)
                            Console.Write(", ");
                    }
                    Console.WriteLine("]");
                }
            }
            else
            {
                Console.WriteLine("Tensor data display is only implemented for 1D and 2D tensors.");
            }
        }

        /// <summary>
        /// Converts the tensor data to a 1D array.
        /// </summary>
        /// <returns>1D array containing tensor data.</returns>
        public T[] ToArray()
        {
            EnsureNotDisposed();

            T[] array = new T[TotalSize];
            Array.Copy(sharedData.Data, offset, array, 0, TotalSize);
            return array;
        }

        /// <summary>
        /// Serializes the tensor to a JSON string.
        /// </summary>
        /// <returns>JSON representation of the tensor.</returns>
        public string ToJson()
        {
            EnsureNotDisposed();
            return JsonSerializer.Serialize(new SerializedTensor<T>
            {
                Shape = this.shape,
                Data = this.ToArray()
            });
        }

        /// <summary>
        /// Deserializes a JSON string to create a tensor.
        /// </summary>
        /// <param name="json">JSON string representing a tensor.</param>
        /// <returns>Deserialized tensor.</returns>
        public static Tensor<T> FromJson(string json)
        {
            if (string.IsNullOrEmpty(json))
                throw new ArgumentException("JSON string cannot be null or empty.", nameof(json));

            var deserialized = JsonSerializer.Deserialize<SerializedTensor<T>>(json);

            if (deserialized == null)
                throw new InvalidOperationException("Failed to deserialize tensor. Deserialized object is null.");

            if (deserialized.Shape == null || deserialized.Data == null)
                throw new InvalidOperationException("Deserialized tensor has null Shape or Data.");

            if (deserialized.Data.Length != deserialized.Shape.Aggregate(1, (a, b) => a * b))
                throw new InvalidOperationException("Data length does not match shape.");

            Tensor<T> tensor = new Tensor<T>(deserialized.Shape);
            Array.Copy(deserialized.Data, 0, tensor.sharedData.Data, tensor.offset, tensor.TotalSize);
            return tensor;
        }

        /// <summary>
        /// Internal class for serialization.
        /// </summary>
        private class SerializedTensor<TData> where TData : unmanaged
        {
            public int[]? Shape { get; set; }
            public TData[]? Data { get; set; }
        }

        #endregion
    }
}

that class would be backbone for neural network library. your requirement adhering to code best practices and academic knowledge, I want to know if there is any improvements that we can implement on this class to make it better for real world application. also I want prompt that describe this class, that would explain this class meta information to any LLM so from that prompt any LLM would understand this class functions and be able to use it in implementing other classes like Layer, Dense Layer etc.., I don't want to write the class code everytime when I want to build new thing on it. if you have any questions please let me know