using System.Collections;
using UnityEngine;

public class EnemyTarget : MonoBehaviour, IDamageable
{
    public static int RemainingObjectives { get; private set; }
    public static event System.Action<int> ObjectiveCountChanged;

    [Header("Health")]
    public float maxHealth = 60f;
    public bool countsAsObjective = true;

    [Header("Combat")]
    public bool canAttack = true;
    public float attackRange = 28f;
    public float attackDamage = 12f;
    public float attackCooldown = 1.3f;
    public Color tracerColor = new Color(1f, 0.35f, 0.25f);

    [Header("Movement")]
    public Vector3 patrolAxis = Vector3.zero;
    public float patrolAmplitude = 0f;
    public float patrolSpeed = 1f;

    [Header("References")]
    public Transform muzzlePoint;

    private static Material _sharedTracerMaterial;

    private float _currentHealth;
    private float _nextAttackTime;
    private Vector3 _startPosition;
    private PlayerHealth _playerHealth;
    private Transform _playerTarget;
    private Renderer[] _renderers;
    private Color[] _baseColors;
    private bool _destroyed;

    public static void ResetObjectives()
    {
        RemainingObjectives = 0;
        ObjectiveCountChanged?.Invoke(RemainingObjectives);
    }

    public static void RecalculateObjectivesInScene()
    {
        EnemyTarget[] targets = FindObjectsOfType<EnemyTarget>(true);
        int total = 0;
        for (int i = 0; i < targets.Length; i++)
        {
            if (targets[i] != null && targets[i].countsAsObjective)
            {
                total++;
            }
        }

        RemainingObjectives = total;
        ObjectiveCountChanged?.Invoke(RemainingObjectives);
    }

    public void Initialize(PlayerHealth playerHealth, Transform playerTarget)
    {
        _playerHealth = playerHealth;
        _playerTarget = playerTarget;
    }

    private void Awake()
    {
        _currentHealth = maxHealth;
        _startPosition = transform.position;
        _renderers = GetComponentsInChildren<Renderer>();
        _baseColors = new Color[_renderers.Length];
        for (int i = 0; i < _renderers.Length; i++)
        {
            _baseColors[i] = _renderers[i].material.color;
        }

        if (countsAsObjective)
        {
            RemainingObjectives++;
            ObjectiveCountChanged?.Invoke(RemainingObjectives);
        }
    }

    private void Start()
    {
        SnapToSurface();
        _startPosition = transform.position;

        if (_playerHealth == null)
        {
            _playerHealth = FindObjectOfType<PlayerHealth>();
        }

        if (_playerTarget == null && _playerHealth != null)
        {
            Camera playerCamera = _playerHealth.GetComponentInChildren<Camera>(true);
            _playerTarget = playerCamera != null ? playerCamera.transform : _playerHealth.transform;
        }
    }

    private void SnapToSurface()
    {
        if (_renderers == null || _renderers.Length == 0)
        {
            return;
        }

        Bounds bounds = _renderers[0].bounds;
        for (int i = 1; i < _renderers.Length; i++)
        {
            bounds.Encapsulate(_renderers[i].bounds);
        }

        float currentBottomY = bounds.min.y;
        Vector3 rayOrigin = bounds.center + Vector3.up * 20f;
        RaycastHit[] hits = Physics.RaycastAll(rayOrigin, Vector3.down, 60f, ~0, QueryTriggerInteraction.Ignore);
        if (hits.Length == 0)
        {
            return;
        }

        System.Array.Sort(hits, (a, b) => a.distance.CompareTo(b.distance));
        for (int i = 0; i < hits.Length; i++)
        {
            if (hits[i].collider == null || hits[i].collider.transform.IsChildOf(transform))
            {
                continue;
            }

            float offsetY = hits[i].point.y - currentBottomY;
            if (Mathf.Abs(offsetY) > 0.01f)
            {
                transform.position += Vector3.up * offsetY;
            }

            break;
        }
    }

    private void Update()
    {
        if (_destroyed)
        {
            return;
        }

        if (patrolAmplitude > 0.01f && patrolAxis.sqrMagnitude > 0.001f)
        {
            Vector3 offset = patrolAxis.normalized * Mathf.Sin(Time.time * patrolSpeed) * patrolAmplitude;
            transform.position = _startPosition + offset;
        }

        if (!canAttack || _playerHealth == null || _playerHealth.IsDead || _playerTarget == null)
        {
            return;
        }

        Vector3 aimPoint = _playerTarget.position;
        Vector3 flatDirection = aimPoint - transform.position;
        flatDirection.y = 0f;
        if (flatDirection.sqrMagnitude > 0.001f)
        {
            Quaternion targetRotation = Quaternion.LookRotation(flatDirection.normalized, Vector3.up);
            transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, Time.deltaTime * 5f);
        }

        Vector3 fireOrigin = muzzlePoint != null ? muzzlePoint.position : transform.position + transform.forward * 0.8f + Vector3.up * 1.2f;
        Vector3 direction = (aimPoint - fireOrigin).normalized;
        if (Vector3.Distance(fireOrigin, aimPoint) > attackRange || Time.time < _nextAttackTime)
        {
            return;
        }

        if (Physics.Raycast(fireOrigin, direction, out RaycastHit hit, attackRange, ~0, QueryTriggerInteraction.Ignore))
        {
            PlayerHealth hitPlayer = hit.collider.GetComponentInParent<PlayerHealth>();
            if (hitPlayer != null)
            {
                _nextAttackTime = Time.time + attackCooldown;
                hitPlayer.TakeDamage(attackDamage);
                ShowTracer(fireOrigin, hit.point, tracerColor);
            }
        }
    }

    public void TakeDamage(float amount, Vector3 hitPoint, Vector3 hitNormal)
    {
        if (_destroyed)
        {
            return;
        }

        _currentHealth -= amount;
        StartCoroutine(FlashHit());

        if (_currentHealth <= 0f)
        {
            DestroyTarget();
        }
    }

    private IEnumerator FlashHit()
    {
        for (int i = 0; i < _renderers.Length; i++)
        {
            _renderers[i].material.color = Color.white;
        }

        yield return new WaitForSeconds(0.08f);

        for (int i = 0; i < _renderers.Length; i++)
        {
            if (_renderers[i] != null)
            {
                _renderers[i].material.color = _baseColors[i];
            }
        }
    }

    private void DestroyTarget()
    {
        _destroyed = true;

        if (countsAsObjective)
        {
            RemainingObjectives = Mathf.Max(0, RemainingObjectives - 1);
            ObjectiveCountChanged?.Invoke(RemainingObjectives);
        }

        GameObject burst = GameObject.CreatePrimitive(PrimitiveType.Sphere);
        Destroy(burst.GetComponent<Collider>());
        burst.transform.position = transform.position + Vector3.up;
        burst.transform.localScale = Vector3.one * 0.75f;
        Renderer burstRenderer = burst.GetComponent<Renderer>();
        burstRenderer.material = new Material(Shader.Find("Standard"));
        burstRenderer.material.color = new Color(1f, 0.45f, 0.15f);
        Destroy(burst, 0.18f);

        Destroy(gameObject);
    }

    private void ShowTracer(Vector3 start, Vector3 end, Color color)
    {
        GameObject tracer = new GameObject("EnemyTracer");
        LineRenderer renderer = tracer.AddComponent<LineRenderer>();
        renderer.material = GetTracerMaterial();
        renderer.positionCount = 2;
        renderer.SetPosition(0, start);
        renderer.SetPosition(1, end);
        renderer.startWidth = 0.045f;
        renderer.endWidth = 0.015f;
        renderer.startColor = color;
        renderer.endColor = new Color(color.r, color.g, color.b, 0.05f);
        renderer.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
        renderer.receiveShadows = false;

        Destroy(tracer, 0.07f);
    }

    private static Material GetTracerMaterial()
    {
        if (_sharedTracerMaterial == null)
        {
            _sharedTracerMaterial = new Material(Shader.Find("Sprites/Default"));
        }

        return _sharedTracerMaterial;
    }
}
