using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Threading;
using System.Threading.Tasks;
using System.Linq;
public class ShootAction : BaseAction
{
    public event EventHandler<onShootEventArgs> onShoot;
    public static event EventHandler<onShootEventArgs> onAnyShoot;

    public class onShootEventArgs : EventArgs {
        public Unit targetUnit;
        public Unit shootingUnit;
    }
    private enum State {
        Idle,
        Aiming,
        Shooting,
        Cooloff
    }
    private State state;
    private float stateTimer;
    private Unit targetUnit;
    private bool canShootBullet;

    float shootingStateTime = 0.1f;
    float cooloffStateTime = 0.5f;
    float aimingStateTime = 1f;
    private Vector3 aimStartDirectionVector;
    private Vector3 aimEndDirectionVector;

    private void Start() {
        actionCost = 1;
        maxDistance = (Range)7;
    }
    private void Update() {
        if (!IsActive()) {
            return;
        }
        
        stateTimer -= Time.deltaTime;

        switch (state) {
            case State.Aiming:
                float rotateSpeed = 2;
                float timeElapsed = (aimingStateTime - stateTimer) * rotateSpeed;
                if (timeElapsed > aimingStateTime) {
                    timeElapsed = aimingStateTime;
                }
                transform.forward = Vector3.Lerp(aimStartDirectionVector
                                         ,aimEndDirectionVector
                                         ,timeElapsed / aimingStateTime) ;
                break;
            case State.Shooting:
                if (canShootBullet) {
                    Shoot();
                    canShootBullet = false;
                }
                break;
        }
        if (IsStateTimerElapsed()) {
            NextState();
        }
    }

    private void NextState() {
        switch (state) {
            case State.Idle:
                aimStartDirectionVector = transform.forward;        
                aimEndDirectionVector = ( targetUnit.GetWorldPosition() - transform.position).normalized;
                state = State.Aiming;
                canShootBullet = true;
                SetTimer(aimingStateTime);
                break;
            case State.Aiming:                    
                state = State.Shooting;
                SetTimer(shootingStateTime);
                break;
            case State.Shooting:
                state = State.Cooloff;
                SetTimer(cooloffStateTime);
                break;
            case State.Cooloff:
                StopAction();
                //state = State.Idle;
                break;
        }        
    }

    public void Shoot() {
        onShoot?.Invoke(this, new onShootEventArgs{
            targetUnit = targetUnit,
            shootingUnit = unit
        });
        onAnyShoot?.Invoke(this, new onShootEventArgs{
            targetUnit = targetUnit,
            shootingUnit = unit
        });
        
        targetUnit.Damage(40);
    }
    private bool IsStateTimerElapsed() => (stateTimer <= 0f);
    private void SetTimer(float time) {
        stateTimer = time;
    }
    public override CancellationToken TakeAction(in GridPosition targetGridPosition, out CancellationToken cancellationToken) {
        targetUnit = LevelGrid.Instance.GetUnitAtGridPosition(targetGridPosition);
        NextState();
        StartAction(out cancellationToken).Register(() => {
            state = State.Idle;
        });
        return cancellationToken;
    }

    public override string GetActionName() {
        return "Shoot";
    }
    protected override bool IsValidTargetPositionSpecific(in GridPosition unitGridPosition, in GridPosition testGridPosition) {
        return (LevelGrid.Instance.HasAnyUnitOnGridPosition(testGridPosition)
                && (LevelGrid.Instance.GetUnitAtGridPosition(testGridPosition).IsEnemy() != unit.IsEnemy())
                && (IsClearShot(unitGridPosition, testGridPosition))
                );
    }

    public bool IsClearShot(in GridPosition unitGridPosition, in GridPosition testGridPosition) {
        float unitShoulderHeight = 1.7f;
        return LevelGrid.Instance.IsLineOfSight(unitGridPosition, testGridPosition, unitShoulderHeight);
    }
    public Unit GetTargetUnit() => targetUnit;

    public override EnemyAIAction GetEnemyAIAction(GridPosition gridPosition) =>
        new EnemyAIAction {
            gridPosition = gridPosition,
            actionValue = 100 + Mathf.RoundToInt((1 - LevelGrid.Instance.GetUnitAtGridPosition(gridPosition).GetHealthNormilized()) * 100f),
        };

    public int GetTargetCountAtPosition(GridPosition gridPosition) =>
        GetValidActionGridPosition(gridPosition).Count();
}