﻿using FishNet.Component.Prediction;
using FishNet.Serializing;
using UnityEngine;

namespace FishNet.Component.Prediction
{
    public struct RigidbodyState
    {
        public uint LocalTick;
        public Vector3 Position;
        public Quaternion Rotation;
        public bool IsKinematic;
        public Vector3 Velocity;
        public Vector3 AngularVelocity;

        public RigidbodyState(Rigidbody rb, bool isKinematic, uint tick) : this(rb, tick)
        {
            Position = rb.transform.position;
            Rotation = rb.transform.rotation;
            IsKinematic = isKinematic;
            Velocity = rb.linearVelocity;
            AngularVelocity = rb.angularVelocity;
            LocalTick = tick;

        }

        public RigidbodyState(Rigidbody rb, uint tick)
        {
            Position = rb.transform.position;
            Rotation = rb.transform.rotation;
            IsKinematic = rb.isKinematic;
            Velocity = rb.linearVelocity;
            AngularVelocity = rb.angularVelocity;
            LocalTick = tick;
        }
    }

    public struct Rigidbody2DState
    {
        public uint LocalTick;
        public Vector3 Position;
        public Quaternion Rotation;
        public Vector2 Velocity;
        public float AngularVelocity;
        public bool Simulated;
        public bool IsKinematic;

        public Rigidbody2DState(Rigidbody2D rb, bool simulated, uint tick)
        {
            Position = rb.transform.position;
            Rotation = rb.transform.rotation;
            Velocity = rb.linearVelocity;
            AngularVelocity = rb.angularVelocity;
            Simulated = simulated;
            IsKinematic = rb.isKinematic;
            LocalTick = tick;
        }

        public Rigidbody2DState(Rigidbody2D rb, uint tick)
        {
            Position = rb.transform.position;
            Rotation = rb.transform.rotation;
            Velocity = rb.linearVelocity;
            AngularVelocity = rb.angularVelocity;
            Simulated = rb.simulated;
            IsKinematic = rb.isKinematic;
            LocalTick = tick;
        }
    }
}

public static class RigidbodyStateSerializers
{

    public static void WriteRigidbodyState(this Writer writer, RigidbodyState value)
    {
        writer.WriteTickUnpacked(value.LocalTick);
        writer.WriteVector3(value.Position);
        writer.WriteQuaternion(value.Rotation);
        writer.WriteBoolean(value.IsKinematic);
        if (!value.IsKinematic)
        {
            writer.WriteVector3(value.Velocity);
            writer.WriteVector3(value.AngularVelocity);
        }
    }

    public static RigidbodyState ReadRigidbodyState(this Reader reader)
    {
        RigidbodyState state = new RigidbodyState()
        {
            LocalTick = reader.ReadTickUnpacked(),
            Position = reader.ReadVector3(),
            Rotation = reader.ReadQuaternion(),
            IsKinematic = reader.ReadBoolean()
        };

        if (!state.IsKinematic)
        {
            state.Velocity = reader.ReadVector3();
            state.AngularVelocity = reader.ReadVector3();
        }

        return state;
    }


    public static void WriteRigidbody2DState(this Writer writer, Rigidbody2DState value)
    {
        writer.WriteTickUnpacked(value.LocalTick);
        writer.WriteVector3(value.Position);
        writer.WriteQuaternion(value.Rotation);
        writer.WriteBoolean(value.Simulated);
        writer.WriteBoolean(value.IsKinematic);

        if (value.Simulated)
        {
            writer.WriteVector2(value.Velocity);
            writer.WriteSingle(value.AngularVelocity);
        }
    }

    public static Rigidbody2DState ReadRigidbody2DState(this Reader reader)
    {
        Rigidbody2DState state = new Rigidbody2DState()
        {
            LocalTick = reader.ReadTickUnpacked(),
            Position = reader.ReadVector3(),
            Rotation = reader.ReadQuaternion(),
            Simulated = reader.ReadBoolean(),
            IsKinematic = reader.ReadBoolean()
        };

        if (state.Simulated)
        {
            state.Velocity = reader.ReadVector2();
            state.AngularVelocity = reader.ReadSingle();
        }

        return state;
    }


}

