using UnityEngine;

[RequireComponent(typeof(Rigidbody2D))]
[RequireComponent(typeof(CircleCollider2D))]
public class Ball : MonoBehaviour
{
    public float speed = 8f;
    public float maxSpeed = 15f;
    public float speedIncrease = 0.1f;
    public float maxBounceAngle = 75f; // Maximum angle the ball can bounce
    public float randomBounceIntensity = 0.2f; // Интенсивность случайного отклонения
    public float paddleBounceIntensity = 0.3f; // Дополнительная интенсивность для отскока от ракетки
    public float minVerticalVelocity = 2f; // Минимальная вертикальная скорость
    public Color ballColor = Color.white; // Цвет мяча
    
    [HideInInspector]
    public bool canSpawnBalls = true; // Флаг, определяющий может ли мяч создавать новые мячи
    
    protected Rigidbody2D rb;
    protected bool isPlaying;
    private Vector2 startPosition;
    private Transform paddleTransform;
    private Vector2 offset;
    private Paddle paddle;
    protected Vector2 lastFrameVelocity;

    protected virtual void Start()
    {
        rb = GetComponent<Rigidbody2D>();
        if (rb == null)
        {
            Debug.LogError("Rigidbody2D component is missing!");
            return;
        }

        // Устанавливаем цвет мяча
        SpriteRenderer spriteRenderer = GetComponent<SpriteRenderer>();
        if (spriteRenderer != null)
        {
            spriteRenderer.color = ballColor;
        }

        // Set up physics properties for proper reflection
        rb.collisionDetectionMode = CollisionDetectionMode2D.Continuous;
        rb.velocity = Vector2.zero;
        rb.angularVelocity = 0f;
        rb.gravityScale = 0f;
        rb.sharedMaterial = new PhysicsMaterial2D
        {
            bounciness = 1f,
            friction = 0f
        };

        var collider = GetComponent<CircleCollider2D>();
        if (collider == null)
        {
            Debug.LogError("CircleCollider2D component is missing!");
            return;
        }

        Debug.Log("Ball components initialized successfully");
        startPosition = transform.position;
        
        // Find the paddle
        GameObject paddleObj = GameObject.FindGameObjectWithTag("Paddle");
        if (paddleObj != null)
        {
            paddleTransform = paddleObj.transform;
            paddle = paddleObj.GetComponent<Paddle>();
            // Calculate initial offset from paddle
            offset = transform.position - paddleTransform.position;
        }
        else
        {
            Debug.LogError("Paddle not found! Make sure it has the 'Paddle' tag.");
        }
        
        PrepareNewBall();
    }

    protected virtual void Update()
    {
        if (!isPlaying)
        {
            // Stick to the paddle
            if (paddleTransform != null)
            {
                transform.position = paddleTransform.position + (Vector3)offset;
            }
            
            // Launch on space or left mouse click
            if (Input.GetButtonDown("Fire1") || Input.GetKeyDown(KeyCode.Space))
            {
                LaunchBall();
            }
        }
        else
        {
            // Maintain constant speed without changing direction
            if (rb.velocity.magnitude != speed)
            {
                rb.velocity = rb.velocity.normalized * speed;
            }
        }
        
        // Сохраняем скорость предыдущего кадра
        lastFrameVelocity = rb.velocity;
    }

    void LaunchBall()
    {
        isPlaying = true;

        // Get base launch velocity (upward direction)
        Vector2 launchVelocity = Vector2.up * speed;

        // Add paddle's velocity influence if available
        if (paddle != null)
        {
            Vector2 paddleVelocity = paddle.GetLaunchVelocity();
            launchVelocity += paddleVelocity;
            
            // Ensure the ball always goes upward regardless of paddle movement
            if (launchVelocity.y < speed * 0.5f)
            {
                launchVelocity.y = speed * 0.5f;
            }
            
            // Normalize and apply speed to maintain consistent velocity
            launchVelocity = launchVelocity.normalized * speed;
        }

        rb.velocity = launchVelocity;
    }

    public void PrepareNewBall()
    {
        isPlaying = false;
        rb.velocity = Vector2.zero;
        
        if (paddleTransform != null)
        {
            // Reset position relative to paddle
            transform.position = paddleTransform.position + (Vector3)offset;
        }
        else
        {
            transform.position = startPosition;
        }
    }

    protected virtual void OnCollisionEnter2D(Collision2D collision)
    {
        if (!isPlaying) return;

        // Get the incoming direction
        Vector2 inDirection = lastFrameVelocity.normalized;
        
        if (collision == null)
        {
            Debug.LogError("Collision is null!");
            return;
        }

        // Special handling for paddle collisions
        if (collision.gameObject.CompareTag("Paddle"))
        {
            HandlePaddleCollision(collision);
            return;
        }

        // For walls and bricks, let physics handle the reflection naturally
        // Just maintain the constant speed without changing the direction
        Vector2 reflected = Vector2.Reflect(lastFrameVelocity.normalized, collision.contacts[0].normal);
        
        // Добавляем случайное отклонение
        float intensity = randomBounceIntensity;
        
        // Применяем случайное отклонение
        reflected = AddRandomness(reflected, intensity);
        
        // Обеспечиваем минимальную вертикальную скорость
        if (Mathf.Abs(reflected.y) < minVerticalVelocity)
        {
            reflected.y = reflected.y < 0 ? -minVerticalVelocity : minVerticalVelocity;
            // Нормализуем вектор и сохраняем скорость
            reflected = reflected.normalized;
        }

        // Применяем скорость, сохраняя текущую величину
        float currentSpeed = lastFrameVelocity.magnitude;
        rb.velocity = reflected * Mathf.Min(currentSpeed, maxSpeed);
    }

    void HandlePaddleCollision(Collision2D collision)
    {
        rb = GetComponent<Rigidbody2D>();
        Paddle paddle = collision.gameObject.GetComponent<Paddle>();
        if (paddle == null) return;

        // Get the paddle's velocity
        Vector2 paddleVel = paddle.GetBounceVelocity();
        
        // Calculate hit position relative to paddle center (-1 to 1)
        float hitPosition = (transform.position.x - collision.transform.position.x) / 
                          (collision.collider.bounds.size.x / 2f);
        
        // Calculate base bounce angle
        float bounceAngle = hitPosition * maxBounceAngle;
        float angleRad = bounceAngle * Mathf.Deg2Rad;
        
        // Calculate base reflection direction
        Vector2 baseDirection = new Vector2(Mathf.Sin(angleRad), Mathf.Cos(angleRad));

        // Calculate incoming velocity relative to paddle
        Vector2 relativeVelocity = rb.velocity - paddleVel;
        
        // Calculate reflection velocity
        Vector2 reflection = Vector2.Reflect(relativeVelocity.normalized, collision.contacts[0].normal);
        
        // Combine base direction with reflection and paddle velocity
        Vector2 finalDirection = (baseDirection + reflection.normalized).normalized;
        
        // Add paddle velocity influence
        Vector2 newVelocity = finalDirection * speed + paddleVel * 0.5f;
        
        // Ensure the ball always goes upward
        if (newVelocity.y < speed * 0.2f)
        {
            newVelocity.y = speed * 0.2f;
            newVelocity = newVelocity.normalized * speed;
        }
        
        // Добавляем случайное отклонение
        float intensity = randomBounceIntensity + paddleBounceIntensity;
        
        // Применяем случайное отклонение
        newVelocity = AddRandomness(newVelocity, intensity);
        
        // Обеспечиваем минимальную вертикальную скорость
        if (Mathf.Abs(newVelocity.y) < minVerticalVelocity)
        {
            newVelocity.y = newVelocity.y < 0 ? -minVerticalVelocity : minVerticalVelocity;
            // Нормализуем вектор и сохраняем скорость
            newVelocity = newVelocity.normalized;
        }

        // Применяем скорость, сохраняя текущую величину
        float currentSpeed = lastFrameVelocity.magnitude;
        rb.velocity = newVelocity * Mathf.Min(currentSpeed, maxSpeed);
        
        // Легкая вибрация при отскоке от ракетки
        if (HapticManager.Instance != null)
        {
            HapticManager.Instance.LightTap();
        }
    }

    Vector2 AddRandomness(Vector2 direction, float intensity)
    {
        // Генерируем случайный угол в радианах
        float randomAngle = Random.Range(-intensity * Mathf.PI / 3f, intensity * Mathf.PI / 3f);
        
        // Поворачиваем вектор на случайный угол
        float cos = Mathf.Cos(randomAngle);
        float sin = Mathf.Sin(randomAngle);
        return new Vector2(
            direction.x * cos - direction.y * sin,
            direction.x * sin + direction.y * cos
        ).normalized;
    }

    void OnTriggerEnter2D(Collider2D other)
    {
        Debug.Log("Triggered");
        // If ball hits the bottom of the screen
        if (other.CompareTag("DeathZone"))
        {
            Debug.Log("Ball hit DeathZone");
            GameManager.Instance.LoseBall(this);
        }
    }
}
