using System.Linq;
using UnityEngine;
using UnityEngine.Assertions;
using Unity.Netcode;
using System.Collections.Generic;

[System.Serializable]
public class Rope
{
    public Point[] points;
    public Stick[] sticks;

    public Rope() {}

    public Rope(Point[] points, Stick[] sticks)
    {
        this.points = points;
        this.sticks = sticks;
    }

    public float CalculateLengthOvershoot()
    {
        float sum = 0f;
        foreach (Stick stick in sticks)
        {
            Debug.DrawRay(stick.B.position, (stick.A.position - stick.B.position).normalized * stick.desiredLength);
            float dist = Vector3.Distance(stick.A.position, stick.B.position);
            sum += dist - stick.desiredLength;
        }
        return sum;
    }

    public static float CalcDiff(Rope r1, Rope r2, bool excludeZ = true)
    {
        if (r1.points.Length != r2.points.Length)
        {
            throw new System.ArgumentException("Ropes are not the same length");
        }

        float diff = 0;
        if (excludeZ)
        {
            for (int i = 0; i < r1.points.Length; i++)
            {
                Vector3 p1, p2;
                p1 = new Vector2(r1.points[i].position.x, r1.points[i].position.y);
                p2 = new Vector2(r2.points[i].position.x, r2.points[i].position.y);
                diff += Vector2.Distance(p1, p2);
            }
        }
        else
        {
            for (int i = 0; i < r1.points.Length; i++)
            {
                diff += Vector3.Distance(r1.points[i].position, r2.points[i].position);
            }
        }
        return diff;
    }

    public static NetworkRope ToNetworkRope(Rope rope)
    {
        return new NetworkRope
        {
            positions = rope.points.Select(p => p.position).ToArray(),
            prevPositions = rope.points.Select(p => p.prevPosition).ToArray(),
            locked = rope.points.Select(p => p.locked).ToArray(),

            // sPosA = rope.sticks.Select(s => s.A.position).ToArray(),
            // sPrevPosA = rope.sticks.Select(s => s.A.prevPosition).ToArray(),
            // sPosB = rope.sticks.Select(s => s.B.position).ToArray(),
            // sPrevPosB = rope.sticks.Select(s => s.B.prevPosition).ToArray(),
            // dead = rope.sticks.Select(s => s.dead).ToArray(),
        };
    }

    public static Rope FromNetworkRope(NetworkRope nrope, float stickLength)
    {
        Assert.IsTrue(nrope.positions.Length == nrope.prevPositions.Length);
        Point[] points = new Point[nrope.positions.Length];
        for (int i = 0; i < nrope.positions.Length; i++)
        {
            points[i] = new Point(nrope.positions[i], nrope.prevPositions[i], nrope.locked[i]);
        }

        RopeBuilder builder = new RopeBuilder(new List<Point>(points), new List<Stick>());

        for (int i = 0; i < (points.Length - 1); i++)
        {
            builder.ConnectPointsWithDesiredLength(i, i + 1, desiredLength: stickLength);
        }

        return builder.Build();
    }

    /* public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
    {
        int pLen = 0;
        int sLen = 0;

        if (serializer.IsWriter)
        {
            pLen = points.Length;
            sLen = sticks.Length;
        }

        serializer.SerializeValue(ref pLen);
        serializer.SerializeValue(ref sLen);

        if (serializer.IsReader)
        {
            points = new Point[pLen];
            sticks = new Stick[sLen];

            for (int i = 0; i < pLen; i++)
            {
                serializer.GetFastBufferReader().ReadValueSafe(out points[i]);
            }

            for (int i = 0; i < sLen; i++)
            {
                serializer.GetFastBufferReader().ReadValueSafe(out sticks[i]);
            }
        }
        else
        {
            for (int i = 0; i < pLen; i++)
            {
                points[i].NetworkSerialize(serializer);
            }

            for (int i = 0; i < sLen; i++)
            {
                sticks[i].NetworkSerialize(serializer);
            }
        }
    } */
}

public struct NetworkRope : INetworkSerializable
{
    // For rope points
    public Vector3[] positions;
    public Vector3[] prevPositions;
    public bool[] locked;

    // For rope sticks
    // public Vector3[] sPosA;
    // public Vector3[] sPrevPosA;
    //
    // public Vector3[] sPosB;
    // public Vector3[] sPrevPosB;
    //
    // public bool[] dead;

    public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
    {
        int positionsLen = 0;
        int prevPositionsLen = 0;
        int lockedLen = 0;
        // int sPosALen = 0;
        // int sPrevPosALen = 0;
        // int sPosBLen = 0;
        // int sPrevPosBLen = 0;
        // int deadLen = 0;

        if (!serializer.IsReader)
        {
            positionsLen = positions.Length;
            prevPositionsLen = prevPositions.Length;
            lockedLen = locked.Length;

            // sPosALen = sPosA.Length;
            // sPrevPosALen = sPrevPosA.Length;
            // sPosBLen = sPosB.Length;
            // sPrevPosBLen = sPrevPosB.Length;
            // deadLen = dead.Length;
        }

        serializer.SerializeValue(ref positionsLen);
        serializer.SerializeValue(ref prevPositionsLen);
        serializer.SerializeValue(ref lockedLen);
        // serializer.SerializeValue(ref sPosALen);
        // serializer.SerializeValue(ref sPrevPosALen);
        // serializer.SerializeValue(ref sPosBLen);
        // serializer.SerializeValue(ref sPrevPosBLen);
        // serializer.SerializeValue(ref deadLen);

        if (serializer.IsReader)
        {
            positions = new Vector3[positionsLen];
            prevPositions = new Vector3[prevPositionsLen];
            locked = new bool[lockedLen];

            // sPosA = new Vector3[sPosALen];
            // sPrevPosA = new Vector3[sPrevPosALen];
            // sPosB = new Vector3[sPosBLen];
            // sPrevPosB = new Vector3[sPrevPosBLen];
            // dead = new bool[deadLen];
        }

        for (int i = 0; i < positionsLen; i++)
        {
            serializer.SerializeValue(ref positions[i]);
        }

        for (int i = 0; i < prevPositionsLen; i++)
        {
            serializer.SerializeValue(ref prevPositions[i]);
        }

        for (int i = 0; i < lockedLen; i++)
        {
            serializer.SerializeValue(ref locked[i]);
        }

/*         for (int i = 0; i < sPosALen; i++)
        {
            serializer.SerializeValue(ref sPosA[i]);
        }

        for (int i = 0; i < sPrevPosALen; i++)
        {
            serializer.SerializeValue(ref sPrevPosA[i]);
        }

        for (int i = 0; i < sPosBLen; i++)
        {
            serializer.SerializeValue(ref sPosB[i]);
        }

        for (int i = 0; i < sPrevPosBLen; i++)
        {
            serializer.SerializeValue(ref sPrevPosB[i]);
        }

        for (int i = 0; i < deadLen; i++)
        {
            serializer.SerializeValue(ref dead[i]);
        } */
    }
}