using MiniJSON;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Player : MonoBehaviour
{
    private Item netItem;
    public bool ForceLocal;

    public bool IsLocal
    {
        get
        {
            return ForceLocal || (netItem != null && netItem.IsLocal);
        }
    }

    private UIHookup uiHookup;

    private CharacterController charControl;

    private PlayerFade playerFade;
    private Vector3 fadeSpot;
    private Camera playerFadeCam;
    private Transform fadeCamRoot;
    private Vector3 startCamShift;
    private Vector3 endCamShift;
    private float camHeight;
    private float camOffsetZ;

    public float DefaultMaxHealth = 1;
    private float maxHealth = 0;
    private float health = 0;

    // Start is called before the first frame update
    void Awake()
    {
        if (shiftTween == null) shiftTween = new SimpleTween();
        shiftTween.Stop();
        netItem = GetComponentInChildren<Item>();
        castLight = transform.Find("CastLight").gameObject;

        uiHookup = FindObjectOfType<UIHookup>();

        if (ForceLocal)
        {
            StartLocal();
        }

        viewRadius = DefaultViewRadius;
    }

    public GameObject PlayerMesh;

    private GameObject castLight;
    private float bottomOffset;
    public float BottomOffset { get { return bottomOffset; } }
    void StartLocal()
    {
        maxHealth = DefaultMaxHealth;
        health = DefaultMaxHealth;
        castLight.SetActive(true);
        charControl = GetComponentInChildren<CharacterController>();
        charControl.enabled = true;

        bottomOffset = -charControl.center.y + charControl.height * 0.5f;

        playerFade = FindObjectOfType<PlayerFade>();
        if (playerFade != null)
        {
            playerFadeCam = playerFade.GetComponent<Camera>();

            fadeSpot = transform.position;

            if (playerFadeCam != null)
            {
                fadeCamRoot = playerFadeCam.transform.root;

                
                startCamShift = playerFadeCam.transform.localPosition;
                camHeight = startCamShift.y;
                camOffsetZ = startCamShift.z;

                ShiftCamera();

                // shift instantly in the XZ plane
                fadeCamRoot.position = SlowFollowXZ(transform.position, fadeCamRoot.position, 1);
            }
        }

        //netItem.GetNetHost().SpawnItemLocal("test",
        //    i =>
        //    {
        //        i.transform.position = transform.position;
        //    }
        //);
    }

    void TakeDamage(object detailsObj)
    {
        Dictionary<string, object> details = detailsObj as Dictionary<string, object>;
        if (details != null && details.ContainsKey("damage"))
        {
            float damage = details.Key("damage", Convert.ToSingle);
            health -= damage;
            if (health < 0)
            {
                health = 0;
                // TODO die
            }

            //Rect hRect = uiHookup.Health.rect;
            //hRect.width = uiHookup.HealthWidth * 
            Vector3 scale = uiHookup.Health.localScale;
            scale.x = (health / maxHealth); ;
            uiHookup.Health.localScale = scale;
        }
    }

    private SimpleTween shiftTween;
    private void ShiftCamera()
    {
        startCamShift = playerFadeCam.transform.localPosition;

        endCamShift = new Vector3(UnityEngine.Random.Range(-0.5f, 0.5f), camHeight + UnityEngine.Random.Range(-0.4f, 0.4f), UnityEngine.Random.Range(camOffsetZ - 0.4f, camOffsetZ + 0.4f));

        shiftTween.Init(v => playerFadeCam.transform.localPosition = startCamShift * (1 - v) + endCamShift * v, SimpleTween.QuadEaseInOut, 0, 1, UnityEngine.Random.Range(5f, 10f));
        shiftTween.OnFinish = ShiftCamera;
    }

    private void OnDestroy()
    {
        shiftTween.Stop();
    }

    void StartRemote()
    {
        if (PlayerMesh != null)
        {
            foreach (MeshRenderer mr in PlayerMesh.GetComponentsInChildren<MeshRenderer>())
            {
                if (mr.sharedMaterial.name == "Player")
                {
                    Material m = mr.material;

                    m.DisableKeyword("_EMISSION");
                    m.globalIlluminationFlags = MaterialGlobalIlluminationFlags.EmissiveIsBlack;
                    m.SetColor("_EmissionColor", Color.black);
                }
            }
        }
    }

    public float Speed;

    private List<Touch> touches = new List<Touch>();

    public float MoveTouchFullZone = 0.7f;
    public float MoveTouchRadiusSize = 1.45f;

    public float DefaultViewRadius = 5.5f;
    private float viewRadius;

    public float CamFollowAmount = 0.9f;
    public float SpotFollowAmount = 0.95f;

    private Vector3 SlowFollowXZ(Vector3 target, Vector3 current, float factor)
    {
        Vector2 currentXZ = new Vector2(current.x, current.z);

        Vector2 targetXZ = new Vector2(target.x, target.z);

        float followThisFrame = 1 - Mathf.Pow(1 - factor, Time.deltaTime);

        Vector2 newCurrentXZ = targetXZ * followThisFrame + currentXZ * (1 - followThisFrame);

        current.x = newCurrentXZ.x;
        current.z = newCurrentXZ.y;

        return current;
    }

    // Update is called once per frame
    void Update()
    {
        if (IsLocal && charControl != null)
        {
            RaycastHit hit;
            if (Physics.Raycast(new Ray(transform.position, Vector3.down), out hit, 10f))
            {
                Vector3 pos = transform.position;
                pos.y = hit.point.y + (bottomOffset + 0.01f);
                transform.position = pos;
            }

            Vector3 wantMove = new Vector3();

            if (Input.GetKey(KeyCode.UpArrow))
            {
                wantMove.z += 1;
            }
            if (Input.GetKey(KeyCode.DownArrow))
            {
                wantMove.z -= 1;
            }
            if (Input.GetKey(KeyCode.RightArrow))
            {
                wantMove.x += 1;
            }
            if (Input.GetKey(KeyCode.LeftArrow))
            {
                wantMove.x -= 1;
            }

            wantMove.Normalize();

            if (uiHookup != null && uiHookup.MoveTouch != null && uiHookup.MainCanvas != null)
            {
                float radius = uiHookup.MoveTouch.rect.width * 0.5f * MoveTouchRadiusSize;

                touches.Clear();
                touches.AddRange(Input.touches);

                if (Input.GetMouseButton(0))
                {
                    touches.Add(new Touch { position = Input.mousePosition });
                }

                foreach (Touch touch in touches)
                {
                    Vector2 diff = new Vector2();
                    RectTransformUtility.ScreenPointToLocalPointInRectangle(uiHookup.MoveTouch, touch.position, null, out diff);
                    if (diff.magnitude < radius)
                    {
                        wantMove = new Vector3(diff.x, 0, diff.y) / (radius * MoveTouchFullZone);
                        if (wantMove.magnitude > 1) wantMove.Normalize();
                    }
                }
            }

            if (playerFade != null && playerFadeCam != null)
            {
                Vector3 playerScreen3 = playerFadeCam.WorldToScreenPoint(fadeSpot);
                Vector3 edgeScreen3 = playerFadeCam.WorldToScreenPoint(fadeSpot + playerFadeCam.transform.right * viewRadius);

                Vector2 playerScreen2 = new Vector2(playerScreen3.x / playerFadeCam.pixelWidth, playerScreen3.y / playerFadeCam.pixelHeight);
                Vector2 edgeScreen2 = new Vector2(edgeScreen3.x / playerFadeCam.pixelWidth, edgeScreen3.y / playerFadeCam.pixelHeight);

                float radius = (edgeScreen2 - playerScreen2).magnitude;

                playerFade.SetFadeParams(radius, playerScreen2);

                fadeCamRoot.position = SlowFollowXZ(transform.position, fadeCamRoot.position, SpotFollowAmount);
                //playerFadeCam.transform.LookAt(fadeCamRoot, Vector3.up);
                fadeSpot = SlowFollowXZ(transform.position, fadeSpot, CamFollowAmount);
            }


            if (wantMove.sqrMagnitude > 0)
            {
                wantMove *= Speed * Time.deltaTime;
                wantMove.y = -0.1f * Time.deltaTime;
                CollisionFlags flags = charControl.Move(wantMove);


            }

            
        }
    }
}
