using UnityEngine;

public class BallBase : MonoBehaviour
{
    public AudioClip spawnSound;

    public AudioClip bounceSound;

    public AudioClip hitSound;

    protected Animator animator;

    protected AudioSource audioSource;

    protected Vector2 speed;

    protected bool affectedByMagnet = true;

    protected bool magnetActiveLeftRight = false;

    protected bool magnetActiveTopBottom = false;

    protected struct MagnetBounceAxisState
    {
        public bool magnetWasActive;
        public bool bouncingToAnchor;
        public float anchor;
        public float target;
        public float bounceTimer;
        public int sideDirection;
    }

    void OnTriggerEnter2D(Collider2D other)
    {
        if(other.gameObject.CompareTag("Bar"))
        {
            if (!audioSource.isPlaying)
            {
                audioSource.PlayOneShot(hitSound);
            }

            // Destroy all bar segments when the ball hits a bar.
            var barSegments = GameObject.FindGameObjectsWithTag("Bar");

            foreach (var barSegment in barSegments)
            {
                Destroy(barSegment);
            }

            // Notify the player that the bar has been hit.
            var player = GameObject.FindGameObjectWithTag("Player");

            if (player != null)
            {
                player.GetComponent<Player>().OnBarHit();
            }
        }
    }

    public void MagnetActive(bool flipped)
    {
        if (flipped)
        {
            magnetActiveTopBottom = true;
        }
        else
        {
            magnetActiveLeftRight = true;
        }
    }

    public void MagnetInactive()
    {
        magnetActiveTopBottom = false;
        magnetActiveLeftRight = false;
    }

    protected float ApplyMagnetBounceAxis(
        float currentValue,
        float minBound,
        float maxBound,
        bool magnetIsActive,
        ref MagnetBounceAxisState state,
        float colliderExtent,
        float bounceDuration,
        float centerLeeway)
    {
        if (!magnetIsActive)
        {
            state.magnetWasActive = false;
            state.sideDirection = 0;
            state.bounceTimer = 0.0f;
            return currentValue;
        }

        float center = (minBound + maxBound) * 0.5f;
        float halfSpan = (maxBound - minBound) * 0.5f;
        float maxLeeway = Mathf.Max(0.0f, halfSpan - colliderExtent);
        float safeLeeway = Mathf.Clamp(centerLeeway, 0.0f, maxLeeway);
        float leftAnchorMax = center - safeLeeway;
        float rightAnchorMin = center + safeLeeway;

        if (!state.magnetWasActive)
        {
            state.magnetWasActive = true;
            state.anchor = currentValue;
            state.sideDirection = state.anchor <= center ? -1 : 1;
            state.target = state.sideDirection < 0 ? minBound + colliderExtent : maxBound - colliderExtent;
            state.bouncingToAnchor = false;
            state.bounceTimer = 0.0f;
        }

        // Keep the selected side locked while magnet is active.
        if (state.sideDirection < 0)
        {
            state.anchor = Mathf.Min(state.anchor, leftAnchorMax);
        }
        else
        {
            state.anchor = Mathf.Max(state.anchor, rightAnchorMin);
        }

        state.bounceTimer += Time.fixedDeltaTime;
        float t = Mathf.Clamp01(state.bounceTimer / bounceDuration);

        if (state.bouncingToAnchor)
        {
            // Mirror NukeBall ascent: ease-out from target back to anchor.
            float easedT = 1.0f - Mathf.Pow(1.0f - t, 2.0f);
            currentValue = Mathf.Lerp(state.target, state.anchor, easedT);

            if (t >= 1.0f)
            {
                state.bouncingToAnchor = false;
                state.bounceTimer = 0.0f;
                currentValue = state.anchor;
            }
        }
        else
        {
            // Mirror NukeBall descent: ease-in from anchor down to side target.
            float easedT = t * t;
            currentValue = Mathf.Lerp(state.anchor, state.target, easedT);

            if (t >= 1.0f)
            {
                state.bouncingToAnchor = true;
                state.bounceTimer = 0.0f;
                currentValue = state.target;
            }
        }

        return currentValue;
    }

    protected bool TryCacheGameBoardBounds(out Bounds bounds)
    {
        var gameBoard = FindAnyObjectByType<GameBoard>();
        if (gameBoard != null)
        {
            return TryGetWorldBounds(gameBoard.gameObject, out bounds);
        }

        bounds = default;
        return false;
    }

    protected static bool TryGetWorldBounds(GameObject target, out Bounds bounds)
    {
        Collider2D collider2D = target.GetComponent<Collider2D>();
        if (collider2D != null)
        {
            bounds = collider2D.bounds;
            return true;
        }

        Renderer renderer = target.GetComponent<Renderer>();
        if (renderer != null)
        {
            bounds = renderer.bounds;
            return true;
        }

        Collider collider3D = target.GetComponent<Collider>();
        if (collider3D != null)
        {
            bounds = collider3D.bounds;
            return true;
        }

        bounds = default;
        return false;
    }
}
