using System.Collections;
using System.Collections.Generic;
using Mirror;
using UnityEngine;

public class NetPlayer : NetworkBehaviour
{

    public Behaviour[] LocalComponents;
    public SpriteRenderer characterSprite;
    [SyncVar]
    public bool insideDoor;
    public LayerMask friendLayer;
    public List<NetPlayer> touchingNeighbours = new List<NetPlayer>();
    [SyncVar]
    public Color pColor;
    [SyncVar]
    public string playerName;
    public Color[] playerColors;
    void Start()
    {
        DontDestroyOnLoad(gameObject);
        if (!isLocalPlayer)
        {
            // gameObject.layer = LayerMask.NameToLayer("Gnd");
            //GetComponent<BoxCollider2D>().size = new Vector2(GetComponent<BoxCollider2D>().size.x/2f,GetComponent<BoxCollider2D>().size.y);
            foreach (Behaviour localComponent in LocalComponents)
            {
                localComponent.enabled = false;
            }
        }
        if (isLocalPlayer)
        {
            SceneData.localPlayer = gameObject;
            // if(SceneData.netSceneData==null){Debug.Log("Scene Data is not init yet");}else{
            //     transform.position = SceneData.netSceneData.spawnPoint.position;
            // }
            ReturnToSpawn();
        }
        if(isServer){
            pColor = playerColors[NetworkServer.connections.Count-1];
        }

        GetComponent<SpriteRenderer>().color = pColor;
    }

    public void ReturnToSpawn()
    {
        if (isServer)
        {
            StartCoroutine(returnToSpawn());
        }
        else
        {
            CmdReturnToSpawn();
        }
    }

    [Command]
    void CmdReturnToSpawn()
    {
        StartCoroutine(returnToSpawn());
    }

    IEnumerator returnToSpawn()
    {
        while (SceneData.netSceneData == null)
        {
            yield return new WaitForSeconds(0.1f);
        }
        while (SceneData.netSceneData.spawnPoint == null)
        {
            yield return new WaitForSeconds(0.1f);
        }
        transform.position = SceneData.netSceneData.spawnPoint.position;

    }
    [SyncVar]
    public Transform parentFrnd;
    bool oldFlipVal = false;

    Transform _parentFrnd;

    // [Command]
    // void CmdChangeParent(Transform newParent)
    // {
    //     transform.parent = newParent;
    //     RpcChangeParent(newParent);
    //     parentFrnd = newParent;
    // }
    // [ClientRpc]
    // void RpcChangeParent(Transform newParent)
    // {
    //     transform.parent = newParent;
    //     parentFrnd = newParent;
    // }
    float t = 0;
    void FixedUpdate()
    {
        if (isServer)
        {
            parentFrnd = getOnFriend();
            if (collisionImpact != Vector3.zero)
            {

                GetComponent<Rigidbody2D>().AddForce(-collisionImpact, ForceMode2D.Impulse);
                collisionImpact = Vector3.zero;
            }

            if (oldFlipVal != characterSprite.flipX)
            {
                if (isServer)
                {
                    RpcFlipX(characterSprite.flipX);
                }
                else
                {
                    CmdFlipX(characterSprite.flipX);
                }
                oldFlipVal = characterSprite.flipX;
            }
        }

        transform.parent = parentFrnd;

        if (transform.parent != null)
        {
            if (t < 1)
            {
                t += Time.deltaTime;
            }
            else
            {
                GetComponent<NetworkTransform>().useLocalSpace = true;
            }
        }
        else
        {
            GetComponent<NetworkTransform>().useLocalSpace = false;
            t = 0;
        }


        if (!isLocalPlayer) { return; }

        // bool someoneOnTop = false;
        // foreach(NetPlayer neighbour in touchingNeighbours){
        //     if(neighbour.parentFrnd == this){
        //         someoneOnTop=true;
        //         break;
        //     }
        // }
        // GetComponent<PlayerController>().isSomeoneOnTop =someoneOnTop;



        if (!isServer) { return; }

    }

    [Command]
    void CmdFlipX(bool value)
    {
        FlipX(value);
        RpcFlipX(value);
    }

    [ClientRpc]
    void RpcFlipX(bool value)
    {
        FlipX(value);
    }

    void FlipX(bool value)
    {
        characterSprite.flipX = value;
    }



    public void CallChangeInsideDoor(bool value)
    {
        if (isServer)
        {
            insideDoor = value;
        }
        else
        {
            CmdChangeInsideDoor(value);
        }
    }
    [Command]
    void CmdChangeInsideDoor(bool value)
    {
        insideDoor = value;
    }


    public Transform getOnFriend()
    {
        Transform friend = null;
        //return (Physics2D.Linecast(transform.position, groundChecker.position, groundLayerMask));
        Collider2D col = GetComponentInChildren<Collider2D>();
        RaycastHit2D hit = Physics2D.BoxCast(col.bounds.center, new Vector2(col.bounds.size.x - (col.bounds.size.x / 5f), col.bounds.size.y), 0, Vector2.down, 0.1f, friendLayer);
        friend = (hit) ? ((hit.collider.transform.GetComponent<NetPlayer>() != null && hit.collider.transform.GetComponent<NetPlayer>() != this) ? hit.collider.transform : null) : null;
        return friend;
    }
    Vector3 collisionImpact;
    void OnCollisionEnter2D(Collision2D col)
    {
        NetPlayer obj = col.collider.transform.GetComponent<NetPlayer>();
        if (obj != null)
        {
            collisionImpact = col.contacts[0].normal * col.contacts[0].relativeVelocity * col.otherRigidbody.mass;
            Debug.Log("Collision impact : " + collisionImpact);
            if (!touchingNeighbours.Contains(obj))
            {
                touchingNeighbours.Add(obj);
            }
        }
    }
    void OnCollisionExit2D(Collision2D col)
    {
        NetPlayer obj = col.collider.transform.GetComponent<NetPlayer>();
        if (obj != null)
        {
            if (touchingNeighbours.Contains(obj))
            {
                touchingNeighbours.Remove(obj);
            }
        }
    }

    void UpdatePushBoxes()
    {
        foreach (PushBox box in FindObjectsOfType<PushBox>())
        {
            box.UpdateNeighbourCount();
        }
    }

    public void OnSceneChanged(){
        if(!isServer){return;}
        foreach(GameObject obj in SceneData.netSceneData.networkObjects){
            GameObject go = Instantiate(obj);
            NetworkServer.Spawn(go, NetworkServer.localConnection);
        }
    }
}
