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

enum CollisionBehavior
{
    Bounce,
    Destroy,
    Stick
}

public class Projectile : MonoBehaviour
{
    // ============================================================
    [Header("Stats")]
    // ============================================================

    [SerializeField]
    private float _maxLifetime = 30.0f;

    [SerializeField]
    private float _baseDamage = 40.0f;

    [SerializeField]
    private bool _onlyDamageWhileMidair = true;

    [SerializeField]
    public bool keepAlive = false;

    // ============================================================
    [Header("Display Properties")]
    // ============================================================

    [SerializeField]
    private CollisionBehavior _collisionBehavior = CollisionBehavior.Destroy;

    [SerializeField]
    private bool _spinOnSpawn = false;

    [SerializeField]
    private float _spinRate = 500f;

    private Rigidbody _rb;
    private Collider _collider;

    private float _spawnTime;
    private bool _canDoDamage = true;

    void Start() {
        _spawnTime = Time.timeSinceLevelLoad;
        StartCoroutine(DespawnRoutine(_maxLifetime));
        _rb = GetComponent<Rigidbody>();
        _collider = GetComponent<Collider>();

        if (_spinOnSpawn) {
            transform.rotation = Quaternion.Euler(
                Random.Range(0f, 360f),
                Random.Range(0f, 360f),
                Random.Range(0f, 360f)
            );
            Vector3 spin = (new Vector3(
                Random.Range(0f, 1f),
                Random.Range(0f, 1f),
                Random.Range(0f, 1f)
            )).normalized * _spinRate;
            _rb.AddTorque(spin);
        }
    }

    void Update() {
        DespawnIfMotionless();
        if (_onlyDamageWhileMidair) {
            _canDoDamage = !IsGrounded();
        }
    }

    IEnumerator DespawnRoutine(float wait) {
        yield return new WaitForSeconds(wait);
        if (keepAlive == false) {
            Destroy(gameObject);
        }
    }

    void DespawnIfMotionless() {
        if (Time.timeSinceLevelLoad - _spawnTime > 1f && _rb && _rb.velocity.sqrMagnitude == 0) {
            StartCoroutine(DespawnRoutine(1f));
        }
    }

    void OnCollisionEnter(Collision collision) {
        if (_canDoDamage == false) {
            return;
        }
        GameObject otherGO = collision.gameObject;
        Rigidbody otherRB = collision.rigidbody;
        switch (otherGO.tag) {
            case "Enemy": {
                    Enemy enemy = otherGO.GetComponent<Enemy>();
                    float projectileSpeed = _rb.velocity.magnitude;
                    enemy.TakeDamage(_baseDamage);
                    otherRB.velocity = transform.forward * 4f;

                    if (_collisionBehavior == CollisionBehavior.Destroy) {
                        Destroy(gameObject);
                    } else if (_collisionBehavior == CollisionBehavior.Stick) {
                        Vector3 oldPosition = transform.position;
                        Quaternion oldRotation = transform.rotation;
                        transform.parent = otherGO.transform;
                        Destroy(GetComponent<Collider>());
                        Destroy(_rb);
                        transform.position = oldPosition;
                        transform.rotation = oldRotation;
                    }
                }
                return;
        }
    }

    bool IsGrounded() {
        if (_collider == null) return false;
        float distanceToGround = _collider.bounds.extents.y;
        return Physics.CheckCapsule(
            _collider.bounds.center,
            new Vector3(
                _collider.bounds.center.x,
                _collider.bounds.min.y - 0.1f,
                _collider.bounds.center.z
            ),
            0.18f,
            LayerMask.GetMask("Terrain")
        );
    }
}
