using UnityEngine;
using UnityEngine.UI;

public class PlayerBehaviour : MonoBehaviour {

    [SerializeField] private float moveSpeed = 5f;
    [SerializeField] private float jumpPower = 5000f;
    [SerializeField] private float maxYSpeed = 1f;
    [SerializeField] private float maxTimeUnderWater = 30f;
    [SerializeField] private GameObject oxygen = null;
    [SerializeField] private Color underWaterColor = new Color(0.21f, 0.44f, 0.47f, 0.5f);

    public static float timeBeforeDyingAtNight = 30f;

    public static Vector3 originalPosition = Vector3.zero;

    public static bool isInLadder = false;

    public static bool isLookingItem = false;

    private const float collisionMargin = 1f;

    private static bool isInWater = false;

    private static float currentBubbleTime = 0f;

    private static bool canJump = true;

    private static Image[] bubbles = null;

    private static Rigidbody rb = null;

    private static RaycastHit hit;

    private const float waterGravityFactor = 3f;

    private static float timePerBubble = 0f;

    private static int currentBubbleIndex = 0;

    private static PlayerBehaviour instance = null;

    private static Vector2 originalBubbleSize = Vector2.zero;

    private static GameObject oxygenStatic = null;

    private static bool justDied = false;

    void Start() {
        if (instance != null) {
            Debug.LogError("Error : only one instance of PlayerBehaviour must be running at a time !");
            return;
        }
        instance = this;
        rb = GetComponent<Rigidbody>();
        originalPosition = transform.position;
        bubbles = oxygen.GetComponentsInChildren<Image>();
        originalBubbleSize = new Vector2(bubbles[0].rectTransform.rect.width, bubbles[0].rectTransform.rect.height);
        timePerBubble = maxTimeUnderWater / bubbles.Length;
        oxygen.SetActive(false);
        oxygenStatic = oxygen;
        if (Application.loadedLevelName.Contains("4")) {
            // On a le méga saut
            jumpPower *= 5;
        }
    }

	void Update() {
        if (!Bed.isSleeping && !FenteTelescope.isInTelescope) {
            if (Input.GetButtonDown("Jump") && (canJump || isInWater) && !isLookingItem) {
                rb.AddForce(Vector3.up * jumpPower, ForceMode.Impulse);
                Vector3 vel = rb.velocity;
                vel.y = Mathf.Clamp(rb.velocity.y, 0, maxYSpeed);
                rb.velocity = vel;
                canJump = false;
                if (isInWater) {
                    if (!SoundManager.SoundIsPlaying("swim")) {
                        SoundManager.PlaySound("swim");
                    }
                }
            }
            if (isInWater) {
                SetBubbleSize(currentBubbleIndex, originalBubbleSize * (1 - (Time.time - currentBubbleTime) / timePerBubble));
            }
        }
    }

    void FixedUpdate() {
        if (!Bed.isSleeping && !FenteTelescope.isInTelescope && Camera.main != null) {
            Vector3 myForward = Camera.main.transform.forward * Time.deltaTime * moveSpeed;
            myForward.y = 0;
            Vector3 myRight = Camera.main.transform.right * Time.deltaTime * moveSpeed;
            myRight.y = 0;

            Vector3 direction = Input.GetAxis("Horizontal") * myRight + Input.GetAxis("Vertical") * myForward;

            if (!isInLadder && !isLookingItem) {
                transform.Translate(direction);
            } else if (isInLadder) {
                transform.Translate(moveSpeed * Vector3.up * Input.GetAxis("Vertical") * Time.deltaTime);
            }
        }
    }

    void OnCollisionEnter(Collision col) {
        if (col.gameObject.tag == "Ground") {
            canJump = true;
        }
    }

    void OnTriggerEnter(Collider col) {
        if (col.tag == "Water") {
            isInWater = true;
            currentBubbleIndex = bubbles.Length;
            InvokeRepeating("ChangeBubbleIndex", 0, timePerBubble);
            oxygen.SetActive(true);
            SoundManager.PlaySound("dive");
            RenderSettings.fog = true;
            RenderSettings.fogDensity = 0.2f;
            RenderSettings.fogColor = underWaterColor;
            rb.velocity = new Vector3(rb.velocity.x, 0.2f * rb.velocity.y, rb.velocity.z);
            Physics.gravity /= waterGravityFactor;
            if (PickDynamite.pickedDynamite) {
                Sun.FadeToNight();
            }
        } else if (col.tag == "TriggerNight" && Interupt.messageAppeared) {
            Sun.FadeToNight();
        }
    }

    void ChangeBubbleIndex() {
        currentBubbleIndex--;
        currentBubbleTime = Time.time;
        if (currentBubbleIndex < 0) {
            DieAndRespawn();
            SoundManager.PlaySound("drowning");
            currentBubbleIndex = 0;
            CancelInvoke("ChangeBubbleIndex");
        }
    }

    void OnTriggerExit(Collider col) {
        if (col.tag == "Water") {
            isInWater = false;
            currentBubbleTime = 0f;
            oxygen.SetActive(false);
            CancelInvoke("ChangeBubbleIndex");
            ResetOxygen();
            if (!justDied) {
                SoundManager.PlaySound("swim_out");
            }
            RenderSettings.fog = false;
            Physics.gravity *= waterGravityFactor;
        }
    }

    void ResetOxygen() {
        for(int i = 0; i < bubbles.Length; i++) {
            SetBubbleSize(i, originalBubbleSize);
        }
    }

    void SetBubbleSize(int idx, Vector2 size) {
        bubbles[idx].rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, size.x);
        bubbles[idx].rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, size.y);
    }

    public static void SetLadder(bool b) {
        isInLadder = b;
        rb.useGravity = !b;
        if (b) {
            rb.velocity = Vector3.zero;
        }
    }

    public static void DieAndRespawn() {
        justDied = true;
        isInWater = false;
        oxygenStatic.SetActive(false);
        FadeManager.DoFadeOut();
        instance.Invoke("FadeIn", FadeManager.fadeDurationStatic);
    }

    void FadeIn() {
        instance.transform.position = originalPosition;
        SoundManager.StopSound("drowning");
        FadeManager.DoFadeIn();
        instance.Invoke("Rez", FadeManager.fadeDurationStatic);
    }

    void Rez() {
        Physics.gravity = Vector3.down * 19.62f;
        justDied = false;
    }

    public static bool IsInLadder() {
        return isInLadder; 
    }
}