using System;
using UnityEngine;

public class DetectionSystem : MonoBehaviour
{
    public enum DetectionStage
    {
        Stage0,
        Stage1,
        Stage2,
        Stage3
    }

    [SerializeField] private DetectionStage _dStage = DetectionStage.Stage0;
    public DetectionStage DStage { get { return _dStage; } private set { _dStage = value; } }
    public event Action<DetectionStage> OnDetectionStageChanged;

    [Header("Target")] 
    [SerializeField] private LayerMask _targetLayers;
    [SerializeField] private Transform _targetCharacter; // 타겟 캐릭터
    [SerializeField] private Vector3 _lastKnownPosition; // 마지막으로 알려진 위치
    [SerializeField] private Vector3 _suspiciousPosition; // 의심스러운 위치
    
    
    [Header("Sight Detection")]
    [SerializeField] private float _fieldOfViewAngle = 120f; // 시야각
    [SerializeField] private float _maxSightDistance = 40f; // 최대 거리
    [SerializeField] private float _detectionDistance = 20f; // 감지 거리
    [SerializeField] private float _recognitionDistance = 15f; // 인식 거리
    [SerializeField] private LayerMask _obstacleLayers; // 장애물 레이어
    
    [Header("Hearing Detection")]
    [SerializeField] private float _maxAudioDistanse = 25f; // 청각 감지 최대 거리
    
    private bool _isTargetInSight = false; // 타겟이 시야에 있는지 여부
    private float _currentTransitionTimer = 0f; // 전환 타이머
    private float _targetTransitionDuration = 0f; // 전환 지속 시간
    
    public Transform TargetCharacter { get => _targetCharacter; set => _targetCharacter = value; }
    public Vector3 LastKnownPosition { get => _lastKnownPosition; set => _lastKnownPosition = value; }
    public Vector3 SuspiciousPosition { get => _suspiciousPosition; set => _suspiciousPosition = value; }
    public bool IsTargetInSight { get => _isTargetInSight; set => _isTargetInSight = value; }  

    private void Awake()
    {
        if (TargetCharacter == null)
        {
            Collider[] hitColliders = Physics.OverlapSphere(transform.position, _maxSightDistance, _targetLayers);
            Transform closestTarget = null;
            float minDistance = Mathf.Infinity;

            foreach (var hitCollider in hitColliders)
            {
                float distance = Vector3.Distance(transform.position, hitCollider.transform.position);
                if (distance < minDistance)
                {
                    minDistance = distance;
                    closestTarget = hitCollider.transform;
                }
            }
            
            if (closestTarget != null)
            {
                TargetCharacter = closestTarget;
            }
            else
            {
                Debug.LogWarning("No target found within sight distance.");
            }
        }
    }

    private void Update()
    {
        SightDetection();
        UpdateDetectionStage();
    }
    
    private void UpdateDetectionStage(DetectionStage newStage)
    {
        if (_dStage != newStage)
        {
            _dStage = newStage;
            OnDetectionStageChanged?.Invoke(_dStage);
            _currentTransitionTimer = 0f;
        }
    }

    private void SightDetection()
    {
        _isTargetInSight = false;
        if (TargetCharacter == null) return; 
        
        Vector3 directionToTarget = (TargetCharacter.position - transform.position).normalized;
        float distanceToTarget = Vector3.Distance(TargetCharacter.position, transform.position);
        float angleToTarget = Vector3.Angle(transform.forward, directionToTarget);

        if (angleToTarget < _fieldOfViewAngle / 2f) // 나누기 2 하는 이유 : 시야각이 중심 기준 좌로 60/ 우로 60으로 측정했기 떄문임
        {
            if (distanceToTarget <= _maxSightDistance) // 최대 거리 확인 : 역전환 3->2 갈떄 사용
            {
                RaycastHit hit;
                Vector3 rayOrigin = transform.position + Vector3.up * 0.5f;
                // 레이캐스팅 필터링을 위해 레이어 2개 사용 (장애물, 타겟)
                if (Physics.Raycast(rayOrigin, directionToTarget, out hit, distanceToTarget,
                        _obstacleLayers | _targetLayers))
                {
                    // 타겟인가?
                    if (hit.transform == TargetCharacter)
                    {
                        IsTargetInSight = true;
                        LastKnownPosition = TargetCharacter.position; // 마지막 본 위치 확인
                    }
                    else
                    {
                        IsTargetInSight = false;
                    }
                }
                else
                {
                    IsTargetInSight = false;
                }
            }
        }
    }

    private void UpdateDetectionStage()
    {
        DetectionStage stage = _dStage;
        _currentTransitionTimer += Time.deltaTime;

        switch (_dStage)
        {
            case DetectionStage.Stage0:
                // 타겟이라 불릴만한게 최대 거리에 들어왔는가?
                if (IsTargetInSight && Vector3.Distance(TargetCharacter.position, transform.position) <=
                    _detectionDistance)
                {
                    if (_currentTransitionTimer >= 0.5f)
                    {
                        UpdateDetectionStage(DetectionStage.Stage1);
                        _currentTransitionTimer = 0f;
                    }
                }
                else _currentTransitionTimer = 0f;
                
                break;
            
            case DetectionStage.Stage1:
                // 타겟이라 불릴만한게 감지 거리에 들어왔는가?
                if (IsTargetInSight && Vector3.Distance(TargetCharacter.position, transform.position) <=
                    _detectionDistance)
                {
                    if (_currentTransitionTimer >= 1f)
                    {
                        UpdateDetectionStage(DetectionStage.Stage2);
                        _currentTransitionTimer = 0f;
                    }
                }
                else
                {
                    // 이제 역전환 조건 추가하기
                    if (_currentTransitionTimer >= 3f)
                    {
                        UpdateDetectionStage(DetectionStage.Stage0);
                        _currentTransitionTimer = 0f;
                    }
                }
                
                break;
            
            case DetectionStage.Stage2:
                // 타겟이라 불릴만한게 인식 거리에 들어왔는가?
                if(IsTargetInSight && Vector3.Distance(TargetCharacter.position, transform.position) <= _recognitionDistance)
                {
                    UpdateDetectionStage(DetectionStage.Stage3);
                    _currentTransitionTimer = 0f;
                }
                else
                {
                    // 이제 역전환 조건 추가하기
                    if (_currentTransitionTimer >= 5f)
                    {
                        UpdateDetectionStage(DetectionStage.Stage1);
                        _currentTransitionTimer = 0f;
                    }
                }
                
                break;
            
            case DetectionStage.Stage3:
                if (!IsTargetInSight ||
                    Vector3.Distance(TargetCharacter.position, transform.position) <= _maxSightDistance)
                {
                    // 전환 조건이 아닌 역전환 조건만 추가
                    if (_currentTransitionTimer >= 3f)
                    {
                        UpdateDetectionStage(DetectionStage.Stage2);
                        _currentTransitionTimer = 0f;
                    }
                }
                else
                {
                    // 시야내로 돌아왔다? 타이머 리셋 
                    _currentTransitionTimer = 0f;
                }
                break;
        }
        
        
    }
    
}
