using System;
using System.CodeDom;
using System.Collections;
using System.Collections.Generic;
using GGJ24;
using UnityEditor;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;

public class CharacterC : MonoBehaviour
{
    private const float MarginX = 0.001f;

    [SerializeField] private float speed = 1f;
    [SerializeField] private SpriteRenderer characterRenderer = null;
    [SerializeField] private Sprite[] characterSprites = null;
    [SerializeField] private Sprite characterIdle = null;
    [SerializeField] private float moveCoolDown = 0.25f;
    [SerializeField] private Transform arm = null;
    [SerializeField] private BalloonControllerC balloons = null;
    [SerializeField] private List<Transform> backgrounds = null;

    private int moveIndex;
    private float moveTimestamp;
    private bool allowMove;

    private AudioSource audio;

    // Start is called before the first frame update
    void Awake()
    {
        this.audio = this.GetComponent<AudioSource>();
        this.allowMove = true;
        this.GetComponent<TriggerPasserC>().OnTrigger += this.FreeClown;
    }

    // Update is called once per frame
    void Update()
    {
        this.Tick();
    }

    private void Tick()
    {
        float deltaX = this.GetDeltaX();
        this.TickHorizontal(deltaX);
        this.TickBackground();

        this.arm.transform.eulerAngles = new Vector3(0f, 0f, this.GetAngle());

        if (Time.timeSinceLevelLoad < this.moveTimestamp)
        {
            return;
        }

        this.moveTimestamp = Time.timeSinceLevelLoad + this.moveCoolDown;

        this.TickMoveIndex(deltaX);
        this.TickSprite(deltaX);
    }

    private float GetDeltaX()
    {
        return Input.GetAxis("Horizontal") * this.speed * Time.deltaTime;
    }

    private float GetAngle()
    {
        Vector2 rawCoords;

        if (this.HasGamepad())
        {
            StickControl rStick = Gamepad.current.rightStick;
            rawCoords = rStick.value;
        }
        else
        {
            rawCoords = Camera.main.ScreenToWorldPoint(Input.mousePosition) - this.arm.position;
        }

        if (rawCoords.sqrMagnitude < 0.25f)
        {
            rawCoords = Vector2.zero;
        }

        return Vector2.SignedAngle(Vector2.right, rawCoords);
    }

    private bool HasGamepad()
    {
        return 0 < Gamepad.all.Count;
    }

    private void TickHorizontal(float deltaX)
    {
        if (!this.allowMove)
        {
            return;
        }

        Vector3 position = this.transform.position;
        position.x += deltaX;
        position.x = Mathf.Max(0, position.x);
        this.transform.position = position;
    }

    private void TickMoveIndex(float deltaX)
    {
        if (MarginX < deltaX)
        {
            this.moveIndex = (this.moveIndex + 1) % this.characterSprites.Length;
        }
        else if (deltaX < -MarginX)
        {
            this.moveIndex = (this.moveIndex + this.characterSprites.Length - 1) % this.characterSprites.Length;
        }
        else
        {
            this.moveIndex = 0;
        }
    }

    private void TickSprite(float deltaX)
    {
        if ((-MarginX < deltaX) && (deltaX < MarginX))
        {
            this.characterRenderer.sprite = this.characterIdle;
        }
        else
        {
            this.characterRenderer.sprite = this.characterSprites[this.moveIndex];
            this.PlayAudio();
        }            
    }

    private void PlayAudio()
    {
        if (this.audio.isPlaying)
        {
            return;
        }

        this.audio.pitch = 0.9f + 0.2f * UnityEngine.Random.value;
        this.audio.Play();
    }

    private void TickBackground()
    {
        for (int i = 0; i < this.backgrounds.Count; ++i)
        {
            Transform background = this.backgrounds[i];
            Vector3 position = background.position;

            float x = this.transform.position.x;
            float distance = position.x - x;

            if (distance < -32)
            {
                position.x += 64;
                background.position = position;
            }
            else if (32 < distance)
            {
                position.x -= 64;
                background.position = position;
            }
        }
    }

    private void FreeClown(GameObject collider)
    {
        if (collider.tag != "Clown")
        {
            return;
        }

        ClownC clown = collider.GetComponent<ClownC>();
        clown.Free();

        this.balloons.UseRandomBalloon();
    }

    public void StopMoving()
    {
        this.allowMove = false;
    }
}
