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

public class BeamTower : AimTower
{
    [SerializeField] private int maxBounces = 4;
    [SerializeField, Range(0f, 50f)] private float damage = 5f;
    [SerializeField] private LayerMask beamMask;
    private const float k_maxBeamDist = 100f;
    [SerializeField] private LineRenderer beam;
    [SerializeField, Range(0.01f, 20f)] private float attackSecondsDelay = 1f;

    protected override void Awake()
    {
        base.Awake();
    }

    public override void Placed()
    {
        base.Placed();

        horizontalArc.Value.AddListener(UpdateBeam);
        verticalArc.Value.AddListener(UpdateBeam);

        StartCoroutine(AttackLoop());
    }


    private IEnumerator AttackLoop()
    {
        do {
            Vector3 origin = barrel.Tip.position;
            Vector3 rayDir = barrel.transform.forward;

            List<Vector3> hitPoints = new();
            hitPoints.Add(origin);
            for (int i = 0; i < maxBounces; i++)
            {
                Debug.DrawRay(origin, rayDir.normalized * k_maxBeamDist, Color.red, 5f);
                RaycastHit hit;
                if (!Physics.Raycast(origin, rayDir, out hit, k_maxBeamDist, beamMask))
                    break;

                // Is damagable?
                HealthComponent healthComp = hit.collider.gameObject.GetComponent<HealthComponent>();
                if (healthComp != null)
                {
                    Debug.Log($"hitting {healthComp.name} {i}");
                    healthComp.TakeDamage(damage);
                    break;
                }
                hitPoints.Add(hit.point);
                rayDir = Vector3.Reflect(rayDir, hit.normal);
                origin = hit.point;
            }

            beam.positionCount = hitPoints.Count;
            beam.SetPositions(hitPoints.ToArray());
            this.OnAttack?.Invoke();
            yield return new WaitForSeconds(attackSecondsDelay);
        } while (true);
    }

    private void UpdateBeam(float unused) => UpdateBeam();

    private void UpdateBeam()
    {

        Vector3 origin = barrel.Tip.position;
        Vector3 rayDir = barrel.transform.forward;

        List<Vector3> hitPoints = new();
        hitPoints.Add(origin);
        for (int i = 0; i < maxBounces; i++)
        {
            Debug.DrawRay(origin, rayDir.normalized * k_maxBeamDist, Color.red, 5f);
            RaycastHit hit;
            if (!Physics.Raycast(origin, rayDir, out hit, k_maxBeamDist, beamMask))
                break;

            hitPoints.Add(hit.point);
            rayDir = Vector3.Reflect(rayDir, hit.normal);
            origin = hit.point;
        }

        beam.positionCount = hitPoints.Count;
        beam.SetPositions(hitPoints.ToArray());
    }
}